Files
cashier_wx/pages/product/components/goods-modal.vue

930 lines
25 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<up-popup :show="visible" :round="20" mode="bottom" @close="close" :close-on-click-overlay="true">
<view class="" style="height: calc(100vh - 70px);">
<view class="shop_sku" >
<scroll-view scroll-y style="height: calc(100vh - 240px); width: 100%">
<!-- <view class="positionabsolute">
<up-icon name="arrow-down" @click="close" color="#333" size="22"></up-icon>
</view> -->
<view class="positionabsolute">
<up-icon name="close-circle" @click="close" color="#000" size="25"></up-icon>
</view>
<up-swiper :list="goods.images" @change="swiperChange" :current="swiperCurrent" radius="6px"
height="250" @click="prveImgs(goods.images, goods.images[swiperCurrent])">
</up-swiper>
<view class="shop_sku_name">{{ goods.name }}</view>
<view class="shop_sku_description" v-if="isSkuGoods">
{{ goods.shortTitle ? goods.shortTitle : '' }}
</view>
<view v-if="goods.type != 'package'">
<view class="shop_sku_box" v-for="(specOptions, specType) in goods.selectSpecInfo" :key="specType">
<view class="shop_sku_box_name">
{{ specType }}
</view>
<view class="flex-start">
<view class="shop_sku_box_item" v-for="option in specOptions" :key="option"
@click="selectSpec(specType, option)" :class="{
shop_sku_box_item_selected: isSkuSelected(specType, option)
}">
{{ option }}
<view class="shop_sku_box_item_tip"
v-if="goods.result && goods.result.isSoldStock == 1 && selectedSpecs[specType] === option">
<view>售罄</view>
</view>
<view class="shop_sku_box_item_tip"
v-if="goods.result == 'kong' && canSubmit == false && selectedSpecs[specType] === option">
<view>已下架</view>
</view>
</view>
</view>
</view>
</view>
<!-- 套餐 -->
<view v-else>
<view class="shop_sku_box">
<view v-for="(setmenu, setmenuindex) in goods.groupSnap" :key="setmenuindex">
<view class="shop_sku_box_name">{{ setmenu.title }} {{ setmenu.count }}
{{ setmenu.number }}</view>
<view class="flex-start">
<view class="shop_sku_box_item" v-for="(option, goodsid) in setmenu.goods"
:key="goodsid" @click="goodsidClick(setmenuindex, option, goodsid)" :class="{
shop_sku_box_item_selected: isOptionSelected(setmenuindex, option)
}" :disabled="isMaxSelected(setmenuindex) && !isOptionSelected(setmenuindex, option)">
{{ option.proName }}
<text v-if="option.unitName">/{{ option.unitName }}</text>
<view class="shop_sku_box_item_tip" v-if="goods.isSoldStock == 1">
<view>售罄</view>
</view>
</view>
</view>
</view>
</view>
</view>
<!-- 推荐搭配 -->
<view class="u-m-t-48 u-p-30" v-if="goods.relatedRecommendJson.length">
<view class="font-bold u-font-32 ">推荐搭配</view>
<view class="u-flex recommand-goods">
<view class=" item" v-for="(product,index) in goods.relatedRecommendJson" :key="index"
@click="modalAdd(product)">
<view class="relative">
<up-image width="210rpx" height="210rpx" radius="12rpx"
:src="product.coverImg"></up-image>
<view class="vifgoodsImg flex-center"
v-if="product.isSale == 0 || (product.isSaleTime == 0 && !product.isSaleTimeshow) || product.isSoldStock == 1 || (product.isStock == 1 && product.stockNumber <= 0)">
<image v-if="product.isSale == 0" src="@/static/ztt/icon_goods_yxj.svg"
style="width: 200rpx; height: 100%" mode=""></image>
<image v-else-if="product.isSaleTime == 0 && !product.isSaleTimeshow"
src="@/static/ztt/icon_goods_wks.svg" style="width: 200rpx; height: 100%"
mode="">
</image>
<image v-else-if="product.isSoldStock == 1" src="@/static/ztt/icon_goods_sq.svg"
style="width: 200rpx; height: 100%" mode=""></image>
<image v-else-if="product.isStock == 1 && product.stockNumber <= 0"
src="@/static/ztt/icon_goods_kcbz.svg" style="width: 200rpx; height: 100%"
mode="">
</image>
</view>
</view>
<view class="info">
<view class="u-line-2 name u-m-t-10 u-font-32 font-500">
{{product.name}}
</view>
<view class="u-flex u-row-between">
<view class="font-bold u-flex u-col-baseline">
<text class="u-font-24"></text>
<view class="u-font-32">
<GoodsPrice :limitDiscount="cartStore.limitTimeDiscount"
:cart="returnFirstSku(product)" :shopUserInfo="shopUserInfo"
:shopInfo="shopInfo"></GoodsPrice>
</view>
</view>
<view class="btn relative" @click.stop="addGoods(product)">
<up-icon name="plus-circle-fill" color="#E9AB7A" size="25"></up-icon>
<view class="dot" v-if="returnGoodsImCartNum(product)>0">
{{returnGoodsImCartNum(product)}}
</view>
</view>
</view>
</view>
</view>
</view>
</view>
</scroll-view>
<view class="shop_bottom">
<view class="flex-between">
<view class="price price-sku" v-if="goods.type != 'package' && goods.result">
<text class="i"></text>
<view class="num">
<GoodsPrice :limitDiscount="cartStore.limitTimeDiscount" :cart="selSku"
:shopUserInfo="shopUserInfo" :shopInfo="shopInfo"></GoodsPrice>
</view>
<text class="num" v-if="false">
{{
shopInfo.isVip == 1 && shopInfo.isMemberPrice == 1
? goods.result.memberPrice || goods.result.salePrice
: goods.result.salePrice
}}
</text>
<text class="i" v-if="goods.unitName">/{{ goods.unitName }}</text>
<text
v-if="goods.result.suitNum > 1">{{ goods.result.suitNum }}{{ goods.result.unitName }}起点</text>
</view>
<view class="price price-package" v-else>
<text class="i"></text>
<view class="num">
<GoodsPrice :limitDiscount="cartStore.limitTimeDiscount" :cart="goods"
:shopUserInfo="shopUserInfo" :shopInfo="shopInfo"></GoodsPrice>
</view>
<text class="num" v-if="false">
{{
shopInfo.isVip == 1 && shopInfo.isMemberPrice == 1
? goods.memberPrice || goods.salePrice
: goods.salePrice
}}
</text>
<text class="i" v-if="goods.unitName">/{{ goods.unitName }}</text>
<text v-if="goods.suitNum > 1">{{ goods.suitNum }}{{ goods.unitName }}起点</text>
</view>
<view class="operation-wrap" v-if="goods.type != 'package'&&stockNumberIsFull(goods)">
<view class="btn">
<up-icon name="minus-circle-fill" color="#E9AB7A" size="25"
v-if="shopCartNumber > 0"></up-icon>
<view class="btnClick" @click="shopCart('-')"></view>
</view>
<text class="num">{{ shopCartNumber }}</text>
<view class="btn">
<up-icon name="plus-circle-fill" color="#E9AB7A" size="25"></up-icon>
<view class="btnClick" @click="shopCart('+')"></view>
</view>
</view>
</view>
<view class="shop_skuselect flex-start" v-if="selectedSpecsStr">
<view class="shop_skuselectname">{{ selectedSpecsStr }}</view>
</view>
<template v-if="!stockNumberIsFull(goods)">
<view class="addShopping">
库存不足
</view>
</template>
<template v-else>
<template v-if="isSkuGoods">
<view v-if="goods.type == 'package'" class="addShopping package"
:class=" allConditionsSatisfied ? 'active' : ''" @click="submitSelection(goods)">
添加到购物车
</view>
<view v-else class="sku addShopping" :class="shopCartNumber > 0 && canSubmit ? 'active' : ''"
@click="submitSelection(goods)">
添加到购物车
</view>
</template>
<template v-else>
<view class="addShopping single" :class="shopCartNumber > 0 ? 'active' : ''"
@click="submitSelection(goods)">
添加到购物车
</view>
</template>
</template>
</view>
</view>
</view>
</up-popup>
</template>
<script setup>
import {
useNavbarStore
} from '@/stores/navbarStore';
const store = useNavbarStore();
const {
showBack,
rightText,
showSearch,
title,
isTransparent,
height,
hasPlaceholder,
scrollTop
} = toRefs(store);
import {
APIminiAppinfo,
APIminiAppskuinfo,
productRelated
} from '@/common/api/product/product.js';
import dayjs from 'dayjs';
//价格计算辅助函数
import {
limitUtils
} from 'ysk-utils';
import GoodsPrice from '@/components/goods-price.vue';
import {
computed,
inject,
ref,
watch
} from "vue";
const cartStore = inject('cartStore')
const shopUserInfo = inject('shopUserInfo')
const shopInfo = inject('shopInfo')
const props = defineProps({
data: {
type: Object,
default: () => {},
},
goods: {
type: Object,
default: () => {
return {
relatedRecommendJson: []
}
},
},
GoodsIDInCartNumMap: {
type: Object,
default: () => {
return {
}
},
}
});
// / 选择规格的方法
const goodsidClick = (setmenuindex, option, goodsid) => {
if (!selectedOptions.value[setmenuindex]) {
// 如果 selectedOptions.value[setmenuindex] 不存在,初始化一个空数组
selectedOptions.value[setmenuindex] = [];
}
if (isOptionSelected(setmenuindex, option)) {
// 如果已经选中,取消选中
selectedOptions.value[setmenuindex] = selectedOptions.value[setmenuindex].filter((item) => item.proId !==
option.proId);
} else if (!isMaxSelected(setmenuindex)) {
// 如果未达到最大选择数量,添加到选中列表
selectedOptions.value[setmenuindex].push(option);
}
};
// 计算所有选中条件是否都符合
const allConditionsSatisfied = computed(() => {
// 检查 specifications.item.groupSnap 是否存在
if (!props.goods?.groupSnap) {
return false;
}
return props.goods.groupSnap.every((optionGroup, index) => {
// 获取当前索引对应的已选选项,如果不存在则默认为空数组
const selected = selectedOptions.value[index] || [];
// 检查是否达到最大选择数量
const hasEnoughSelection = selected.length === optionGroup.number;
return hasEnoughSelection;
});
});
// 存储用户当前选择的规格,初始为空对象
const selectedSpecs = ref({});
const shopCartNumber = ref(0)
function isSkuSelected(specType, option) {
return selectedSpecs.value[specType] === option;
}
const selSku = ref(null)
// 处理规格选择的方法
const selectSpec = async (specType, option) => {
// 规格清零
shopCartNumber.value = 0;
// 更新 selectedSpecs 对象,将当前规格类型的选中值设置为用户点击的选项
const newSelectedSpecs = {};
const specKeys = Object.keys(props.goods.selectSpecInfo);
for (const key of specKeys) {
if (key === specType) {
newSelectedSpecs[key] = option;
} else {
newSelectedSpecs[key] = selectedSpecs.value[key];
}
}
selectedSpecs.value = newSelectedSpecs;
if (allSpecsSelected.value) {
// try {
let result = await APIminiAppskuinfo({
specInfo: selectedSpecsStr.value,
id: props.goods.id
});
// skuList
if (result != true) {
selSku.value = result
} else {}
} else {}
};
// 判断是否达到最大选择数量
const isMaxSelected = (setmenuindex) => {
// 确保 selectedOptions.value[setmenuindex] 存在
if (selectedOptions.value[setmenuindex]) {
return selectedOptions.value[setmenuindex].length >= props.goods.groupSnap[setmenuindex].number;
}
return false;
};
// 存储选中的选项,二维数组
const selectedOptions = ref(props.goods.groupSnap.map(() => []));
// 判断选项是否已选中
const isOptionSelected = (setmenuindex, option) => {
// 确保 selectedOptions.value[setmenuindex] 存在
if (selectedOptions.value[setmenuindex]) {
return selectedOptions.value[setmenuindex].some((item) => item.proId === option.proId);
}
return false;
};
const canSubmit = computed(() => {
if (shopCartNumber.value <= 0) {
return false
}
return true
})
// 计算属性,将 selectedSpecs 转换为字符串形式
const selectedSpecsStr = computed(() => {
const values = Object.values(selectedSpecs.value);
return values.join('');
});
// 计算属性,判断是否所有规格类型都有选中项
const allSpecsSelected = computed(() => {
// 获取所有规格类型的键
const specKeys = Object.keys(props.goods.selectSpecInfo);
// skuBtnText.value = selectedSpecsStr.value ? `您还没选择${specKeys[1]}哦` : ``
// 检查每个规格类型是否都在 selectedSpecs 中有对应的选中值
return specKeys.every((key) => selectedSpecs.value[key]);
});
const swiperCurrent = ref(0);
function returnFirstSku(product) {
return product.skuList[0]
}
//返回是否是多规格商品
function returnIsSkuGoods(item) {
if (item.type == 'single' || item.type == 'weight' || (item.type == 'package' && item.groupType == '0')) {
return false;
}
return true;
}
const isSkuGoods = computed(() => {
return returnIsSkuGoods(props.goods);
});
function swiperChange(e) {
swiperCurrent.value = e.current;
}
const emits = defineEmits(['prveImgs', 'websocketsendMessage', 'close', 'modalAdd'])
function prveImgs(images, currentUrl) {
emits('prveImgs', images, currentUrl)
}
function modalAdd(item) {
emits('modalAdd', item)
}
const visible = defineModel({
default: false,
});
function stockNumberIsFull(item) {
if (item.isStock && item.stockNumber < item.suitNum) {
return false
}
return true
}
function close() {
visible.value = false;
shopCartNumber.value = 0;
selectedOptions.value = props.goods.groupSnap.map(() => [])
emits('close')
}
function isSelected(option) {
return selectedSpecs.value[specType] === option;
}
const calculateValue = (cartNumber, i, step = 1) => {
if (i == '+') {
const result = parseFloat(cartNumber) + parseFloat(step);
return result.toFixed(2);
} else {
// 当减到0返回del
const result = parseFloat(cartNumber) - parseFloat(step);
return result == 0 ? 'del' : result.toFixed(2);
}
};
// 判断商品是否在可售时间内
const isProductAvailable = async (sellDaysStr, startTimeStr, endTimeStr) => {
// 将后端返回的字符串转换为数组
const sellDays = sellDaysStr.split(',');
const now = dayjs();
const days = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
const currentDay = days[now.day()];
// console.log('当前日期:', currentDay);
// console.log('可售日期列表:', sellDays);
// 检查当前周几是否在可售周几列表中
if (!sellDays.includes(currentDay)) {
// console.log('当前日期不在可售日期列表中');
return false;
}
const startTime = dayjs(`${now.format('YYYY-MM-DD')} ${startTimeStr}`);
let endTime = dayjs(`${now.format('YYYY-MM-DD')} ${endTimeStr}`);
// 处理跨天情况
if (endTime.isBefore(startTime)) {
endTime = endTime.add(1, 'day');
}
// console.log('当前时间:', now.format('YYYY-MM-DD HH:mm:ss'));
// console.log('开始时间:', startTime.format('YYYY-MM-DD HH:mm:ss'));
// console.log('结束时间:', endTime.format('YYYY-MM-DD HH:mm:ss'));
const isInRange = now.isBetween(startTime, endTime, null, '[)');
// console.log('当前时间是否在可售时间范围内:', isInRange);
return isInRange;
};
async function addGoods(goods) {
if (!isProductAvailable(goods.days, goods.startTime,
goods.endTime)) {
uni.showToast({
title: '不在可售时间内'
});
return false;
}
if (goods.isSoldStock == 1 || (goods.isSaleTime == 0 && !goods.isSaleTimeshow)) {
return uni.showToast({
title: '商品已下架或不在可售时间内',
icon: 'none'
});
}
const sku = goods.skuList[0]
const findCart = cartStore.carts.find(cart => cart.product_id == goods.id && sku.id)
emits('websocketsendMessage', {
id: findCart ? findCart.id : '',
type: 'shopping',
suitNum: sku.suitNum,
table_code: uni.cache.get('tableCode'),
shop_id: uni.cache.get('shopId'),
operate_type: findCart ? 'edit' : 'add',
product_id: goods.id,
sku_id: sku.id,
number: findCart ? await calculateValue(findCart.number * 1, '+', 1) : 1,
pro_group_info: '',
goods_type: goods.type == 'package' ? 'package' : '',
memberPrice: goods.memberPrice,
is_print: 1,
product_type: goods.type,
is_time_discount: showLimitDiscount(goods)
})
}
/**
* 返回购物车对应的商品数量
*/
function returnGoodsImCartNum(goods) {
console.log('props.GoodsIDInCartNumMap', props.GoodsIDInCartNumMap)
if (props.GoodsIDInCartNumMap.hasOwnProperty(goods.id)) {
return props.GoodsIDInCartNumMap[goods.id]
}
return 0
}
function returnSelectedGroupSnap() {
if (!props.goods?.groupSnap) {
return '';
}
return props.goods.groupSnap.map((v, index) => {
return {
...v,
goods: selectedOptions.value[index]
}
});
}
// 提交选择并执行下一步操作的方法
const submitSelection = async (goods) => {
if (!isProductAvailable(goods.days, goods.startTime,
goods.endTime)) {
uni.showToast({
title: '不在可售时间内'
});
return false;
}
// 判断购物车是否有该选中商品
if (goods.type != 'package' && shopCartNumber.value <= 0) {
return;
}
if (goods.type == 'package' && !allConditionsSatisfied.value) {
return
}
if ((goods.type == 'package' && allConditionsSatisfied.value) || (goods.type ==
'sku' && canSubmit.value)) {
let res = cartStore.carts.find(cart => cart.product_id == goods.id && cart.sku_id == selSku.value.id)
let suitNum = 1;
let sku_id = ''
// 是否是套餐 有就传
if (goods.type == 'package') {
// 需求更改:所所有商品套餐都是add,没有修改
shopCartNumber.value = props.goods.suitNum;
suitNum = props.goods.suitNum;
sku_id = props.goods.sku_id;
res = null;
} else {
suitNum = selSku.value.suitNum
sku_id = selSku.value.id
}
console.log('goods', goods);
emits('websocketsendMessage', {
id: res ? res.id : '',
type: 'shopping',
suitNum,
table_code: uni.cache.get('tableCode'),
shop_id: uni.cache.get('shopId'),
operate_type: res ? 'edit' : 'add',
product_id: goods.id,
sku_id,
number: res ? await calculateValue(res.cartNumber, '+', shopCartNumber.value) :
shopCartNumber.value,
pro_group_info: returnSelectedGroupSnap(),
goods_type: goods.type == 'package' ? 'package' : '',
memberPrice: goods.memberPrice,
is_print: 1,
product_type: goods.type,
is_time_discount: showLimitDiscount(goods)
})
} else {
let res = cartStore.carts.find(cart => cart.product_id == goods.id && goods.skuList[0].id)
emits('websocketsendMessage', {
id: res ? res.id : '',
type: 'shopping',
suitNum: goods.suitNum,
table_code: uni.cache.get('tableCode'),
shop_id: uni.cache.get('shopId'),
operate_type: res ? 'edit' : 'add',
product_id: goods.id,
sku_id: goods.skuList[0].id,
number: res ? await calculateValue(res.cartNumber, '+', shopCartNumber.value) :
shopCartNumber.value,
memberPrice: goods.memberPrice,
is_print: 1,
product_type: goods.type,
is_time_discount: showLimitDiscount(goods)
})
}
close()
};
function showLimitDiscount(item) {
if (!cartStore.limitTimeDiscount || !cartStore.limitTimeDiscount.id) {
return 0;
}
return limitUtils.canUseLimitTimeDiscount(item, cartStore.limitTimeDiscount, shopInfo, shopUserInfo.value, 'id') ?
1 : 0;
}
// 多规格 套餐 单规格添加数量
const shopCart = async (i) => {
if (i == '-' && shopCartNumber.value <= (props.goods.suitNum || 1)) {
shopCartNumber.value = 0;
return false;
}
let res = null
if (i == '-') {
if (!res && shopCartNumber.value == props.goods.suitNum) {
uni.showToast({
title: `起点${props.goods.suitNum}`,
icon: 'none'
});
return false;
} else {
shopCartNumber.value--;
}
} else {
if (!res && shopCartNumber.value < 1) {
if (props.goods.type == 'sku') {
if (!selSku.value) {
return
}
shopCartNumber.value = parseFloat(selSku.value.suitNum);
} else {
shopCartNumber.value = parseFloat(props.goods.suitNum);
}
} else {
shopCartNumber.value++;
}
}
};
</script>
<style lang="scss" scoped>
.box {
height: 100vh;
display: flex;
flex-direction: column;
.top {
width: 750rpx;
}
}
.shop_sku {
width: 100%;
flex: 1;
position: relative;
border-radius: 20rpx;
background: #fff;
box-sizing: border-box;
overflow: hidden;
.positionabsolute {
position: absolute;
top: 30rpx;
z-index: 999;
right: 30rpx;
}
// .positionabsolute {
// position: absolute;
// top: 30rpx;
// z-index: 999;
// left: 30rpx;
// width: 60rpx;
// height: 60rpx;
// display: flex;
// align-items: center;
// justify-content: center;
// background-color: #eee;
// border-radius: 50%;
// }
.shop_sku_name {
padding: 0 28rpx;
margin-top: 20rpx;
font-weight: bold;
font-size: 32upx;
margin-bottom: 16rpx;
}
.shop_sku_returned {
padding: 0 28rpx;
font-weight: 400;
font-size: 24rpx;
color: #ff534b;
}
.shop_sku_description {
padding: 0 28rpx;
font-weight: 400;
font-size: 24rpx;
color: #999999;
margin-top: 16rpx;
padding-bottom: 32rpx;
box-sizing: border-box;
border-bottom: 2rpx solid #f0f0f0;
}
.shop_sku_box {
padding: 20rpx;
.shop_sku_box_name {
margin-top: 20rpx;
font-weight: 500;
font-size: 28upx;
color: #333;
}
.flex-start {
.shop_sku_box_item {
margin-top: 16rpx;
padding: 12rpx 28rpx;
border-radius: 8rpx;
font-size: 24upx;
margin-right: 56rpx;
background: #efefef;
border: 2rpx solid #efefef;
position: relative;
color: #666666;
.shop_sku_box_item_tip {
width: 62rpx;
height: 47rpx;
text-align: right;
position: absolute;
top: 0;
right: 0;
background: linear-gradient(45deg, transparent, transparent 50%, #cecece 50%, #cecece 100%);
view {
font-size: 18rpx;
color: #666666;
transform: rotate(45deg);
position: absolute;
top: 5rpx;
right: 3rpx;
}
}
}
.shop_sku_box_item:nth-child(1) {
margin-left: 0;
}
.disabled {
color: #999;
background-color: #f5f5f5;
border: 2rpx solid #f5f5f5;
}
.shop_sku_box_item_noselected {
color: #666;
}
.shop_sku_box_item_selected {
background: #fefaf7;
border-radius: 8rpx;
border: 2rpx solid #e8ad7b;
color: #e8ad7b;
}
}
}
.shop_skuselect {
margin-top: 16rpx;
width: 100%;
// background: #f7f7f7;
color: #999;
font-size: 24upx;
.shop_skuselectname {
color: #000;
font-size: 26upx;
}
}
.shop_bottom {
width: 100%;
box-sizing: border-box;
padding: 30rpx 28rpx;
background-color: #fff;
box-shadow: 0rpx -6rpx 14rpx 2rpx rgba(0, 0, 0, 0.1);
.price {
display: flex;
align-items: flex-end;
.i {
font-size: 28rpx;
color: #e8ad7b;
position: relative;
bottom: 4upx;
font-weight: bold;
}
.num {
font-size: 42rpx;
color: #e8ad7b;
position: relative;
top: 6upx;
padding: 0 4upx;
}
}
.operation-wrap {
display: flex;
align-items: center;
.num {
font-size: 32upx;
padding: 0 16upx;
}
.btn {
display: flex;
align-items: center;
justify-content: center;
position: relative;
.btnClick {
width: 100rpx;
height: 100rpx;
position: absolute;
// bottom: 0;
}
}
}
.addShopping {
width: 100%;
height: 96rpx;
line-height: 96rpx;
text-align: center;
background: #ccc;
border-radius: 48rpx;
font-weight: 400;
font-size: 32rpx;
color: #ffffff;
margin-top: 36rpx;
}
.addShopping.active {
background: #e8ad7b;
}
}
}
.recommand-goods {
display: flex;
flex-wrap: wrap;
margin-top: 24rpx;
.item {
display: flex;
flex-direction: column;
align-items: center;
margin-right: 30rpx;
margin-bottom: 30rpx;
width: 210rpx;
&:nth-child(3n) {
margin-right: 0;
}
.name {
height: 84rpx;
}
.info {
width: 100%;
}
}
}
.relative {
position: relative;
}
.dot {
position: absolute;
right: -10rpx;
top: -10rpx;
background-color: #FF534B;
border-radius: 32rpx;
width: 30rpx;
font-size: 20rpx;
color: #fff;
height: 30rpx;
text-align: center;
overflow: hidden;
}
.vifgoodsImg {
width: 100%;
height: 204rpx;
position: absolute;
top: 0;
left: 0;
z-index: 20;
background-color: rgb(0, 0, 0, 0.5);
image {
padding: 30rpx;
width: 100%;
height: 100%;
}
}
</style>