Merge branch 'develop' of https://gitee.com/yudaocode/yudao-mall-uniapp
This commit is contained in:
@@ -0,0 +1,196 @@
|
||||
<!-- TODO 霖:是不是怎么复用 s-count-down 组件 -->
|
||||
<template>
|
||||
<view class="time" :style="justifyLeft">
|
||||
<text class="" v-if="tipText">{{ tipText }}</text>
|
||||
<text
|
||||
class="styleAll p6"
|
||||
v-if="isDay === true"
|
||||
:style="{ background: bgColor.bgColor, color: bgColor.Color }"
|
||||
>{{ day }}{{ bgColor.isDay ? '天' : '' }}</text
|
||||
>
|
||||
<text
|
||||
class="timeTxt"
|
||||
v-if="dayText"
|
||||
:style="{ width: bgColor.timeTxtwidth, color: bgColor.bgColor }"
|
||||
>{{ dayText }}</text
|
||||
>
|
||||
<text
|
||||
class="styleAll"
|
||||
:class="isCol ? 'timeCol' : ''"
|
||||
:style="{ background: bgColor.bgColor, color: bgColor.Color, width: bgColor.width }"
|
||||
>{{ hour }}</text
|
||||
>
|
||||
<text
|
||||
class="timeTxt"
|
||||
v-if="hourText"
|
||||
:class="isCol ? 'whit' : ''"
|
||||
:style="{ width: bgColor.timeTxtwidth, color: bgColor.bgColor }"
|
||||
>{{ hourText }}</text
|
||||
>
|
||||
<text
|
||||
class="styleAll"
|
||||
:class="isCol ? 'timeCol' : ''"
|
||||
:style="{ background: bgColor.bgColor, color: bgColor.Color, width: bgColor.width }"
|
||||
>{{ minute }}</text
|
||||
>
|
||||
<text
|
||||
class="timeTxt"
|
||||
v-if="minuteText"
|
||||
:class="isCol ? 'whit' : ''"
|
||||
:style="{ width: bgColor.timeTxtwidth, color: bgColor.bgColor }"
|
||||
>{{ minuteText }}</text
|
||||
>
|
||||
<text
|
||||
class="styleAll"
|
||||
:class="isCol ? 'timeCol' : ''"
|
||||
:style="{ background: bgColor.bgColor, color: bgColor.Color, width: bgColor.width }"
|
||||
>{{ second }}</text
|
||||
>
|
||||
<text class="timeTxt" v-if="secondText">{{ secondText }}</text>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'countDown',
|
||||
props: {
|
||||
justifyLeft: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
//距离开始提示文字
|
||||
tipText: {
|
||||
type: String,
|
||||
default: '倒计时',
|
||||
},
|
||||
dayText: {
|
||||
type: String,
|
||||
default: '天',
|
||||
},
|
||||
hourText: {
|
||||
type: String,
|
||||
default: '时',
|
||||
},
|
||||
minuteText: {
|
||||
type: String,
|
||||
default: '分',
|
||||
},
|
||||
secondText: {
|
||||
type: String,
|
||||
default: '秒',
|
||||
},
|
||||
datatime: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
isDay: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
isCol: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
bgColor: {
|
||||
type: Object,
|
||||
default: null,
|
||||
},
|
||||
},
|
||||
data: function () {
|
||||
return {
|
||||
day: '00',
|
||||
hour: '00',
|
||||
minute: '00',
|
||||
second: '00',
|
||||
};
|
||||
},
|
||||
created: function () {
|
||||
this.show_time();
|
||||
},
|
||||
mounted: function () {},
|
||||
methods: {
|
||||
show_time: function () {
|
||||
let that = this;
|
||||
|
||||
function runTime() {
|
||||
//时间函数
|
||||
let intDiff = that.datatime - Date.parse(new Date()) / 1000; //获取数据中的时间戳的时间差;
|
||||
let day = 0,
|
||||
hour = 0,
|
||||
minute = 0,
|
||||
second = 0;
|
||||
if (intDiff > 0) {
|
||||
//转换时间
|
||||
if (that.isDay === true) {
|
||||
day = Math.floor(intDiff / (60 * 60 * 24));
|
||||
} else {
|
||||
day = 0;
|
||||
}
|
||||
hour = Math.floor(intDiff / (60 * 60)) - day * 24;
|
||||
minute = Math.floor(intDiff / 60) - day * 24 * 60 - hour * 60;
|
||||
second = Math.floor(intDiff) - day * 24 * 60 * 60 - hour * 60 * 60 - minute * 60;
|
||||
if (hour <= 9) hour = '0' + hour;
|
||||
if (minute <= 9) minute = '0' + minute;
|
||||
if (second <= 9) second = '0' + second;
|
||||
that.day = day;
|
||||
that.hour = hour;
|
||||
that.minute = minute;
|
||||
that.second = second;
|
||||
} else {
|
||||
that.day = '00';
|
||||
that.hour = '00';
|
||||
that.minute = '00';
|
||||
that.second = '00';
|
||||
}
|
||||
}
|
||||
runTime();
|
||||
setInterval(runTime, 1000);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.p6 {
|
||||
padding: 0 8rpx;
|
||||
}
|
||||
.styleAll {
|
||||
/* color: #fff; */
|
||||
font-size: 24rpx;
|
||||
height: 36rpx;
|
||||
line-height: 36rpx;
|
||||
border-radius: 6rpx;
|
||||
text-align: center;
|
||||
/* padding: 0 6rpx; */
|
||||
}
|
||||
.timeTxt {
|
||||
text-align: center;
|
||||
/* width: 16rpx; */
|
||||
height: 36rpx;
|
||||
line-height: 36rpx;
|
||||
display: inline-block;
|
||||
}
|
||||
.whit {
|
||||
color: #fff !important;
|
||||
}
|
||||
.time {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.red {
|
||||
color: #fc4141;
|
||||
margin: 0 4rpx;
|
||||
}
|
||||
|
||||
.timeCol {
|
||||
/* width: 40rpx;
|
||||
height: 40rpx;
|
||||
line-height: 40rpx;
|
||||
text-align:center;
|
||||
border-radius: 6px;
|
||||
background: #fff;
|
||||
font-size: 24rpx; */
|
||||
color: #e93323;
|
||||
}
|
||||
</style>
|
||||
@@ -2,34 +2,81 @@
|
||||
<template>
|
||||
<su-popup :show="show" type="bottom" round="20" @close="emits('close')" showClose>
|
||||
<view class="model-box">
|
||||
<view class="title ss-m-t-16 ss-m-l-20 ss-flex">营销活动</view>
|
||||
<view class="title ss-m-t-16 ss-m-l-20 ss-flex">优惠</view>
|
||||
<view v-if="state.rewardActivity && state.rewardActivity.id > 0">
|
||||
<view class="titleLi">促销</view>
|
||||
<scroll-view
|
||||
class="model-content"
|
||||
scroll-y
|
||||
:scroll-with-animation="false"
|
||||
:enable-back-to-top="true"
|
||||
>
|
||||
<view
|
||||
class="actBox"
|
||||
v-for="(item, index) in getRewardActivityRuleGroupDescriptions(state.rewardActivity)"
|
||||
:key="index"
|
||||
>
|
||||
<view
|
||||
class="boxCont ss-flex ss-col-top ss-m-b-40"
|
||||
@tap="onGoodsList(state.rewardActivity)"
|
||||
>
|
||||
<view class="model-content-tag ss-flex ss-row-center">{{ item.name }}</view>
|
||||
<view class="model-content-title">
|
||||
<view class="contBu">
|
||||
{{ item.values.join(';') }}
|
||||
</view>
|
||||
<view class="ss-m-b-24 cotBu-txt">
|
||||
{{ sheep.$helper.timeFormat(state.rewardActivity.startTime, 'yyyy.mm.dd') }}
|
||||
-
|
||||
{{ sheep.$helper.timeFormat(state.rewardActivity.endTime, 'yyyy.mm.dd') }}
|
||||
</view>
|
||||
</view>
|
||||
<text class="cicon-forward" />
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
<view class="titleLi">可领优惠券</view>
|
||||
<scroll-view
|
||||
class="model-content ss-m-t-50"
|
||||
class="model-content"
|
||||
scroll-y
|
||||
:scroll-with-animation="false"
|
||||
:enable-back-to-top="true"
|
||||
v-if="state.couponInfo.length"
|
||||
>
|
||||
<view v-for="item in state.activityInfo" :key="item.id">
|
||||
<view class="ss-flex ss-col-top ss-m-b-40" @tap="onGoodsList(item)">
|
||||
<view class="model-content-tag ss-flex ss-row-center">满减</view>
|
||||
<view class="ss-m-l-20 model-content-title ss-flex-1">
|
||||
<view class="ss-m-b-24" v-for="rule in state.activityMap[item.id]?.rules" :key="rule">
|
||||
{{ formatRewardActivityRule(state.activityMap[item.id], rule) }}
|
||||
<view class="actBox" v-for="item in state.couponInfo" :key="item.id">
|
||||
<view class="boxCont ss-flex ss-col-top ss-m-b-40">
|
||||
<view class="model-content-tag2">
|
||||
<view class="usePrice"> ¥{{ fen2yuan(item.discountPrice) }} </view>
|
||||
<view class="impose"> 满¥{{ fen2yuan(item.usePrice) }}可用 </view>
|
||||
</view>
|
||||
<view class="model-content-title2">
|
||||
<view class="contBu">
|
||||
{{ item.name }}
|
||||
</view>
|
||||
<view class="ss-m-b-24 cotBu-txt">
|
||||
{{
|
||||
item.validityType == 1
|
||||
? sheep.$helper.timeFormat(item.validStartTime, 'yyyy.mm.dd') -
|
||||
sheep.$helper.timeFormat(item.validEndTime, 'yyyy.mm.dd')
|
||||
: '领取后' + item.fixedStartTerm + '-' + item.fixedEndTerm + '天可用'
|
||||
}}
|
||||
</view>
|
||||
</view>
|
||||
<text class="cicon-forward" />
|
||||
<view class="coupon" @click.stop="getBuy(item.id)" v-if="item.canTake"> 立即领取 </view>
|
||||
<view class="coupon2" v-else> 已领取 </view>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
<view class="nullBox" v-else> 暂无可领优惠券 </view>
|
||||
</view>
|
||||
</su-popup>
|
||||
</template>
|
||||
<script setup>
|
||||
import sheep from '@/sheep';
|
||||
import { computed, reactive, watch } from 'vue';
|
||||
import RewardActivityApi from '@/sheep/api/promotion/rewardActivity';
|
||||
import { formatRewardActivityRule } from '@/sheep/hooks/useGoods';
|
||||
|
||||
import { getRewardActivityRuleGroupDescriptions } from '@/sheep/hooks/useGoods';
|
||||
import { computed, reactive, watch, ref } from 'vue';
|
||||
import { fen2yuan } from '@/sheep/hooks/useGoods';
|
||||
const props = defineProps({
|
||||
modelValue: {
|
||||
type: Object,
|
||||
@@ -42,26 +89,14 @@
|
||||
});
|
||||
const emits = defineEmits(['close']);
|
||||
const state = reactive({
|
||||
activityInfo: computed(() => props.modelValue),
|
||||
activityMap: {}
|
||||
rewardActivity: computed(() => props.modelValue.rewardActivity),
|
||||
couponInfo: computed(() => props.modelValue.couponInfo),
|
||||
});
|
||||
|
||||
watch(
|
||||
() => props.show,
|
||||
() => {
|
||||
// 展示的情况下,加载每个活动的详细信息
|
||||
if (props.show) {
|
||||
state.activityInfo?.forEach(activity => {
|
||||
RewardActivityApi.getRewardActivity(activity.id).then(res => {
|
||||
if (res.code !== 0) {
|
||||
return;
|
||||
}
|
||||
state.activityMap[activity.id] = res.data;
|
||||
})
|
||||
});
|
||||
}
|
||||
},
|
||||
);
|
||||
// 领取优惠劵
|
||||
const getBuy = (id) => {
|
||||
emits('get', id);
|
||||
};
|
||||
|
||||
function onGoodsList(e) {
|
||||
sheep.$router.go('/pages/activity/index', {
|
||||
@@ -72,34 +107,149 @@
|
||||
<style lang="scss" scoped>
|
||||
.model-box {
|
||||
height: 60vh;
|
||||
|
||||
.title {
|
||||
justify-content: center;
|
||||
font-size: 36rpx;
|
||||
height: 80rpx;
|
||||
font-weight: bold;
|
||||
color: #333333;
|
||||
}
|
||||
}
|
||||
|
||||
.model-content {
|
||||
height: fit-content;
|
||||
max-height: 380rpx;
|
||||
padding: 0 20rpx;
|
||||
box-sizing: border-box;
|
||||
margin-top: 20rpx;
|
||||
|
||||
.model-content-tag {
|
||||
background: rgba(#ff6911, 0.1);
|
||||
font-size: 24rpx;
|
||||
// background: rgba(#ff6911, 0.1);
|
||||
font-size: 35rpx;
|
||||
font-weight: 500;
|
||||
color: #ff6911;
|
||||
line-height: 42rpx;
|
||||
width: 68rpx;
|
||||
height: 32rpx;
|
||||
border-radius: 5rpx;
|
||||
line-height: 150rpx;
|
||||
width: 200rpx;
|
||||
height: 150rpx;
|
||||
text-align: center;
|
||||
|
||||
// border-radius: 5rpx;
|
||||
}
|
||||
|
||||
.model-content-title {
|
||||
width: 450rpx;
|
||||
height: 150rpx;
|
||||
font-size: 26rpx;
|
||||
font-weight: 500;
|
||||
color: #333333;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.cicon-forward {
|
||||
font-size: 28rpx;
|
||||
color: #999999;
|
||||
margin: 0 auto;
|
||||
}
|
||||
}
|
||||
|
||||
// 新增的
|
||||
.titleLi {
|
||||
margin: 10rpx 0 10rpx 20rpx;
|
||||
font-size: 26rpx;
|
||||
}
|
||||
|
||||
.actBox {
|
||||
width: 700rpx;
|
||||
height: 150rpx;
|
||||
background-color: #fff2f2;
|
||||
margin: 10rpx auto;
|
||||
border-radius: 10rpx;
|
||||
}
|
||||
|
||||
.boxCont {
|
||||
width: 700rpx;
|
||||
height: 150rpx;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.contBu {
|
||||
height: 80rpx;
|
||||
line-height: 80rpx;
|
||||
overflow: hidden;
|
||||
font-size: 30rpx;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
-o-text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.cotBu-txt {
|
||||
height: 70rpx;
|
||||
line-height: 70rpx;
|
||||
font-size: 25rpx;
|
||||
color: #999999;
|
||||
}
|
||||
|
||||
.model-content-tag2 {
|
||||
font-size: 35rpx;
|
||||
font-weight: 500;
|
||||
color: #ff6911;
|
||||
width: 200rpx;
|
||||
height: 150rpx;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.usePrice {
|
||||
width: 200rpx;
|
||||
height: 90rpx;
|
||||
line-height: 100rpx;
|
||||
// background-color: red;
|
||||
}
|
||||
|
||||
.impose {
|
||||
width: 200rpx;
|
||||
height: 50rpx;
|
||||
// line-height: 75rpx;
|
||||
font-size: 23rpx;
|
||||
// background-color: gold;
|
||||
}
|
||||
|
||||
.model-content-title2 {
|
||||
width: 330rpx;
|
||||
height: 150rpx;
|
||||
font-size: 26rpx;
|
||||
font-weight: 500;
|
||||
color: #333333;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.coupon {
|
||||
width: 150rpx;
|
||||
height: 50rpx;
|
||||
line-height: 50rpx;
|
||||
background-color: rgb(255, 68, 68);
|
||||
color: white;
|
||||
border-radius: 30rpx;
|
||||
text-align: center;
|
||||
font-size: 25rpx;
|
||||
}
|
||||
|
||||
.coupon2 {
|
||||
width: 150rpx;
|
||||
height: 50rpx;
|
||||
line-height: 50rpx;
|
||||
background-color: rgb(203, 192, 191);
|
||||
color: white;
|
||||
border-radius: 30rpx;
|
||||
text-align: center;
|
||||
font-size: 25rpx;
|
||||
}
|
||||
.nullBox {
|
||||
width: 100%;
|
||||
height: 300rpx;
|
||||
font-size: 25rpx;
|
||||
line-height: 300rpx;
|
||||
text-align: center;
|
||||
color: #999999;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -39,6 +39,8 @@
|
||||
<s-groupon-block v-if="type === 'PromotionCombination'" :data="data" :styles="styles" />
|
||||
<!-- 营销组件:秒杀 -->
|
||||
<s-seckill-block v-if="type === 'PromotionSeckill'" :data="data" :styles="styles" />
|
||||
<!-- 营销组件:积分商城 -->
|
||||
<s-point-block v-if="type === 'PromotionPoint'" :data="data" :styles="styles" />
|
||||
<!-- 营销组件:小程序直播(暂时没有这个功能) -->
|
||||
<s-live-block v-if="type === 'MpLive'" :data="data" :styles="styles" />
|
||||
<!-- 营销组件:优惠券 -->
|
||||
|
||||
@@ -15,25 +15,11 @@
|
||||
:scroll-with-animation="false"
|
||||
:enable-back-to-top="true"
|
||||
>
|
||||
<view v-for="(item, index) in state.orderInfo.promo_infos" :key="index">
|
||||
<view class="ss-flex ss-m-b-40 subtitle">
|
||||
<view>共{{ item.goods_ids.length }}件,</view>
|
||||
<view v-if="item.activity_type === 'full_discount'">
|
||||
满{{ item.discount_rule.full }}打{{ item.discount_rule.discount }}折,已减
|
||||
</view>
|
||||
<view v-if="item.activity_type === 'full_gift'">满赠</view>
|
||||
<view v-if="item.activity_type === 'full_reduce'">
|
||||
满{{ item.discount_rule.full }}减{{ item.discount_rule.discount }},已减
|
||||
</view>
|
||||
<view class="price-text">¥{{ item.promo_discount_money || '0.00' }}</view>
|
||||
<view v-for="(item, index) in state.orderInfo.promotions" :key="index">
|
||||
<!-- 不展示积分、优惠劵、会员折扣,因为它们已经单独展示了 -->
|
||||
<view class="ss-flex ss-m-b-40 subtitle" v-if="[1, 2, 3, 4, 5, 6].includes(item.type)">
|
||||
<view> {{ item.description }} </view>
|
||||
</view>
|
||||
<scroll-view class="scroll-box" scroll-x scroll-anchoring>
|
||||
<view class="ss-flex">
|
||||
<view v-for="i in item.goods_ids" :key="i">
|
||||
<image class="content-img" :src="sheep.$url.cdn(getGoodsImg(i))" />
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
@@ -44,7 +30,6 @@
|
||||
</template>
|
||||
<script setup>
|
||||
import { computed, reactive } from 'vue';
|
||||
import sheep from '@/sheep';
|
||||
const props = defineProps({
|
||||
promoInfo: {
|
||||
type: Array,
|
||||
@@ -67,28 +52,22 @@
|
||||
const state = reactive({
|
||||
orderInfo: computed(() => props.modelValue),
|
||||
});
|
||||
const getGoodsImg = (e) => {
|
||||
let goodsImg = '';
|
||||
state.orderInfo.goods_list.forEach((i) => {
|
||||
if (e == i.goods_id) {
|
||||
goodsImg = i.goods.image;
|
||||
}
|
||||
});
|
||||
return goodsImg;
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.model-box {
|
||||
height: 60vh;
|
||||
}
|
||||
|
||||
.model-content {
|
||||
height: 54vh;
|
||||
}
|
||||
|
||||
.modal-footer {
|
||||
width: 100%;
|
||||
height: 120rpx;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.confirm-btn {
|
||||
width: 710rpx;
|
||||
margin-left: 20rpx;
|
||||
@@ -97,17 +76,20 @@
|
||||
border-radius: 40rpx;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.content-img {
|
||||
width: 140rpx;
|
||||
height: 140rpx;
|
||||
margin-right: 20rpx;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
font-size: 28rpx;
|
||||
font-weight: 500;
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
.price-text {
|
||||
color: #ff3000;
|
||||
}
|
||||
|
||||
@@ -144,6 +144,8 @@
|
||||
import { computed, reactive, onMounted } from 'vue';
|
||||
import sheep from '@/sheep';
|
||||
import SpuApi from '@/sheep/api/product/spu';
|
||||
import OrderApi from '@/sheep/api/trade/order';
|
||||
import { appendSettlementProduct } from '@/sheep/hooks/useGoods';
|
||||
|
||||
// 布局类型
|
||||
const LayoutTypeEnum = {
|
||||
@@ -238,6 +240,15 @@
|
||||
onMounted(async () => {
|
||||
// 加载商品列表
|
||||
state.goodsList = await getGoodsListByIds(spuIds.join(','));
|
||||
// 拼接结算信息(营销)
|
||||
await OrderApi.getSettlementProduct(state.goodsList.map((item) => item.id).join(',')).then(
|
||||
(res) => {
|
||||
if (res.code !== 0) {
|
||||
return;
|
||||
}
|
||||
appendSettlementProduct(state.goodsList, res.data);
|
||||
},
|
||||
);
|
||||
// 只有双列布局时需要
|
||||
if (layoutType === LayoutTypeEnum.TWO_COL) {
|
||||
// 分列
|
||||
|
||||
@@ -11,11 +11,7 @@
|
||||
<view v-if="tagStyle.show" class="tag-icon-box">
|
||||
<image class="tag-icon" :src="sheep.$url.cdn(tagStyle.src || tagStyle.imgUrl)"></image>
|
||||
</view>
|
||||
<image
|
||||
class="xs-img-box"
|
||||
:src="sheep.$url.cdn(data.image || data.picUrl)"
|
||||
mode="aspectFit"
|
||||
></image>
|
||||
<image class="xs-img-box" :src="sheep.$url.cdn(data.image || data.picUrl)" mode="aspectFit" />
|
||||
<view
|
||||
v-if="goodsFields.title?.show || goodsFields.name?.show || goodsFields.price?.show"
|
||||
class="xs-goods-content ss-flex-col ss-row-around"
|
||||
@@ -27,13 +23,34 @@
|
||||
>
|
||||
{{ data.title || data.name }}
|
||||
</view>
|
||||
<!-- 活动信息 -->
|
||||
<view class="iconBox" v-if="data.promotionType > 0 || data.rewardActivity">
|
||||
<view class="card" v-if="discountText">{{ discountText }}</view>
|
||||
<view
|
||||
class="card2"
|
||||
v-for="item in getRewardActivityRuleItemDescriptions(data.rewardActivity).slice(0, 1)"
|
||||
:key="item"
|
||||
>
|
||||
{{ item }}
|
||||
</view>
|
||||
</view>
|
||||
<view
|
||||
v-if="goodsFields.price?.show"
|
||||
class="xs-goods-price font-OPPOSANS"
|
||||
:style="[{ color: goodsFields.price.color }]"
|
||||
>
|
||||
<text class="price-unit ss-font-24">{{ priceUnit }}</text>
|
||||
{{ isArray(data.price) ? fen2yuan(data.price[0]) : fen2yuan(data.price) }}
|
||||
<!-- 活动价格 -->
|
||||
<text v-if="data.activityType && data.activityType === PromotionActivityTypeEnum.POINT.type">
|
||||
{{ data.point }}积分
|
||||
{{ !data.pointPrice || data.pointPrice === 0 ? '' : `+${fen2yuan(data.pointPrice)}元` }}
|
||||
</text>
|
||||
<template v-else>
|
||||
<text class="price-unit ss-font-24">{{ priceUnit }}</text>
|
||||
<text v-if="data.promotionPrice > 0">{{ fen2yuan(data.promotionPrice) }}</text>
|
||||
<text v-else>
|
||||
{{ isArray(data.price) ? fen2yuan(data.price[0]) : fen2yuan(data.price) }}
|
||||
</text>
|
||||
</template>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -60,13 +77,34 @@
|
||||
>
|
||||
{{ data.title || data.name }}
|
||||
</view>
|
||||
<!-- 活动信息 -->
|
||||
<view class="iconBox" v-if="data.promotionType > 0 || data.rewardActivity">
|
||||
<view class="card" v-if="discountText">{{ discountText }}</view>
|
||||
<view
|
||||
class="card2"
|
||||
v-for="item in getRewardActivityRuleItemDescriptions(data.rewardActivity).slice(0, 1)"
|
||||
:key="item"
|
||||
>
|
||||
{{ item }}
|
||||
</view>
|
||||
</view>
|
||||
<view
|
||||
v-if="goodsFields.price?.show"
|
||||
class="sm-goods-price font-OPPOSANS"
|
||||
:style="[{ color: goodsFields.price.color }]"
|
||||
>
|
||||
<text class="price-unit ss-font-24">{{ priceUnit }}</text>
|
||||
{{ isArray(data.price) ? fen2yuan(data.price[0]) : fen2yuan(data.price) }}
|
||||
<!-- 活动价格 -->
|
||||
<text v-if="data.activityType && data.activityType === PromotionActivityTypeEnum.POINT.type">
|
||||
{{ data.point }}积分
|
||||
{{ !data.pointPrice || data.pointPrice === 0 ? '' : `+${fen2yuan(data.pointPrice)}元` }}
|
||||
</text>
|
||||
<template v-else>
|
||||
<text class="price-unit ss-font-24">{{ priceUnit }}</text>
|
||||
<text v-if="data.promotionPrice > 0">{{ fen2yuan(data.promotionPrice) }}</text>
|
||||
<text v-else>
|
||||
{{ isArray(data.price) ? fen2yuan(data.price[0]) : fen2yuan(data.price) }}
|
||||
</text>
|
||||
</template>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -74,13 +112,9 @@
|
||||
<!-- md卡片:竖向,一行放两个,图上内容下 -->
|
||||
<view v-if="size === 'md'" class="md-goods-card ss-flex-col" :style="[elStyles]" @tap="onClick">
|
||||
<view v-if="tagStyle.show" class="tag-icon-box">
|
||||
<image class="tag-icon" :src="sheep.$url.cdn(tagStyle.src || tagStyle.imgUrl)"></image>
|
||||
<image class="tag-icon" :src="sheep.$url.cdn(tagStyle.src || tagStyle.imgUrl)" />
|
||||
</view>
|
||||
<image
|
||||
class="md-img-box"
|
||||
:src="sheep.$url.cdn(data.image || data.picUrl)"
|
||||
mode="widthFix"
|
||||
></image>
|
||||
<image class="md-img-box" :src="sheep.$url.cdn(data.image || data.picUrl)" mode="widthFix" />
|
||||
<view
|
||||
class="md-goods-content ss-flex-col ss-row-around ss-p-b-20 ss-p-t-20 ss-p-x-16"
|
||||
:id="elId"
|
||||
@@ -110,16 +144,36 @@
|
||||
</view>
|
||||
</view>
|
||||
</slot>
|
||||
<!-- 活动信息 -->
|
||||
<view class="iconBox" v-if="data.promotionType > 0 || data.rewardActivity">
|
||||
<view class="card" v-if="discountText">{{ discountText }}</view>
|
||||
<view
|
||||
class="card2"
|
||||
v-for="item in getRewardActivityRuleItemDescriptions(data.rewardActivity).slice(0, 1)"
|
||||
:key="item"
|
||||
>
|
||||
{{ item }}
|
||||
</view>
|
||||
</view>
|
||||
<view class="ss-flex ss-col-bottom">
|
||||
<view
|
||||
v-if="goodsFields.price?.show"
|
||||
class="md-goods-price ss-m-t-16 font-OPPOSANS ss-m-r-10"
|
||||
:style="[{ color: goodsFields.price.color }]"
|
||||
>
|
||||
<text class="price-unit ss-font-24">{{ priceUnit }}</text>
|
||||
{{ isArray(data.price) ? fen2yuan(data.price[0]) : fen2yuan(data.price) }}
|
||||
<!-- 活动价格 -->
|
||||
<text v-if="data.activityType && data.activityType === PromotionActivityTypeEnum.POINT.type">
|
||||
{{ data.point }}积分
|
||||
{{ !data.pointPrice || data.pointPrice === 0 ? '' : `+${fen2yuan(data.pointPrice)}元` }}
|
||||
</text>
|
||||
<template v-else>
|
||||
<text class="price-unit ss-font-24">{{ priceUnit }}</text>
|
||||
<text v-if="data.promotionPrice > 0">{{ fen2yuan(data.promotionPrice) }}</text>
|
||||
<text v-else>
|
||||
{{ isArray(data.price) ? fen2yuan(data.price[0]) : fen2yuan(data.price) }}
|
||||
</text>
|
||||
</template>
|
||||
</view>
|
||||
|
||||
<view
|
||||
v-if="
|
||||
(goodsFields.original_price?.show || goodsFields.marketPrice?.show) &&
|
||||
@@ -163,7 +217,7 @@
|
||||
class="lg-img-box"
|
||||
:src="sheep.$url.cdn(data.image || data.picUrl)"
|
||||
mode="aspectFill"
|
||||
></image>
|
||||
/>
|
||||
<view class="lg-goods-content ss-flex-1 ss-flex-col ss-row-between ss-p-b-10 ss-p-t-20">
|
||||
<view>
|
||||
<view
|
||||
@@ -189,21 +243,38 @@
|
||||
</view>
|
||||
</view>
|
||||
</slot>
|
||||
<view class="ss-flex ss-col-bottom ss-m-t-10">
|
||||
<!-- 活动信息 -->
|
||||
<view class="iconBox" v-if="data.promotionType > 0 || data.rewardActivity">
|
||||
<view class="card" v-if="discountText">{{ discountText }}</view>
|
||||
<view
|
||||
v-if="goodsFields.price?.show"
|
||||
class="lg-goods-price ss-m-r-12 ss-flex ss-col-bottom font-OPPOSANS"
|
||||
:style="[{ color: goodsFields.price.color }]"
|
||||
class="card2"
|
||||
v-for="item in getRewardActivityRuleItemDescriptions(data.rewardActivity).slice(0, 1)"
|
||||
:key="item"
|
||||
>
|
||||
<text class="ss-font-24">{{ priceUnit }}</text>
|
||||
{{ isArray(data.price) ? fen2yuan(data.price[0]) : fen2yuan(data.price) }}
|
||||
{{ item }}
|
||||
</view>
|
||||
</view>
|
||||
<view v-if="goodsFields.price?.show" class="ss-flex ss-col-bottom font-OPPOSANS">
|
||||
<view class="sl-goods-price ss-m-r-12" :style="[{ color: goodsFields.price.color }]">
|
||||
<!-- 活动价格 -->
|
||||
<text v-if="data.activityType && data.activityType === PromotionActivityTypeEnum.POINT.type">
|
||||
{{ data.point }}积分
|
||||
{{ !data.pointPrice || data.pointPrice === 0 ? '' : `+${fen2yuan(data.pointPrice)}元` }}
|
||||
</text>
|
||||
<template v-else>
|
||||
<text class="price-unit ss-font-24">{{ priceUnit }}</text>
|
||||
<text v-if="data.promotionPrice > 0">{{ fen2yuan(data.promotionPrice) }}</text>
|
||||
<text v-else>
|
||||
{{ isArray(data.price) ? fen2yuan(data.price[0]) : fen2yuan(data.price) }}
|
||||
</text>
|
||||
</template>
|
||||
</view>
|
||||
<view
|
||||
v-if="
|
||||
(goodsFields.original_price?.show || goodsFields.marketPrice?.show) &&
|
||||
(data.original_price > 0 || data.marketPrice > 0)
|
||||
"
|
||||
class="goods-origin-price ss-flex ss-col-bottom font-OPPOSANS"
|
||||
class="goods-origin-price ss-m-t-16 font-OPPOSANS ss-flex"
|
||||
:style="[{ color: originPriceColor }]"
|
||||
>
|
||||
<text class="price-unit ss-font-20">{{ priceUnit }}</text>
|
||||
@@ -217,22 +288,20 @@
|
||||
</view>
|
||||
|
||||
<slot name="cart">
|
||||
<view class="buy-box ss-flex ss-col-center ss-row-center" v-if="buttonShow"> 去购买 </view>
|
||||
<view class="buy-box ss-flex ss-col-center ss-row-center" v-if="buttonShow"> 去购买</view>
|
||||
</slot>
|
||||
</view>
|
||||
|
||||
<!-- sl卡片:竖向型,一行放一个,图片上内容下边 -->
|
||||
<view v-if="size === 'sl'" class="sl-goods-card ss-flex-col" :style="[elStyles]" @tap="onClick">
|
||||
<view v-if="tagStyle.show" class="tag-icon-box">
|
||||
<image class="tag-icon" :src="sheep.$url.cdn(tagStyle.src || tagStyle.imgUrl)"></image>
|
||||
<image class="tag-icon" :src="sheep.$url.cdn(tagStyle.src || tagStyle.imgUrl)" />
|
||||
</view>
|
||||
|
||||
<image
|
||||
class="sl-img-box"
|
||||
:src="sheep.$url.cdn(data.image || data.picUrl)"
|
||||
mode="aspectFill"
|
||||
></image>
|
||||
|
||||
/>
|
||||
<view class="sl-goods-content">
|
||||
<view>
|
||||
<view
|
||||
@@ -262,10 +331,31 @@
|
||||
</view>
|
||||
</view>
|
||||
</slot>
|
||||
<!-- 活动信息 -->
|
||||
<view class="iconBox" v-if="data.promotionType > 0 || data.rewardActivity">
|
||||
<view class="card" v-if="discountText">{{ discountText }}</view>
|
||||
<view
|
||||
class="card2"
|
||||
v-for="item in getRewardActivityRuleItemDescriptions(data.rewardActivity).slice(0, 1)"
|
||||
:key="item"
|
||||
>
|
||||
{{ item }}
|
||||
</view>
|
||||
</view>
|
||||
<view v-if="goodsFields.price?.show" class="ss-flex ss-col-bottom font-OPPOSANS">
|
||||
<view class="sl-goods-price ss-m-r-12" :style="[{ color: goodsFields.price.color }]">
|
||||
<text class="price-unit ss-font-24">{{ priceUnit }}</text>
|
||||
{{ isArray(data.price) ? fen2yuan(data.price[0]) : fen2yuan(data.price) }}
|
||||
<!-- 活动价格 -->
|
||||
<text v-if="data.activityType && data.activityType === PromotionActivityTypeEnum.POINT.type">
|
||||
{{ data.point }}积分
|
||||
{{ !data.pointPrice || data.pointPrice === 0 ? '' : `+${fen2yuan(data.pointPrice)}元` }}
|
||||
</text>
|
||||
<template v-else>
|
||||
<text class="price-unit ss-font-24">{{ priceUnit }}</text>
|
||||
<text v-if="data.promotionPrice > 0">{{ fen2yuan(data.promotionPrice) }}</text>
|
||||
<text v-else>
|
||||
{{ isArray(data.price) ? fen2yuan(data.price[0]) : fen2yuan(data.price) }}
|
||||
</text>
|
||||
</template>
|
||||
</view>
|
||||
<view
|
||||
v-if="
|
||||
@@ -321,14 +411,17 @@
|
||||
* @event {Function()} click - 点击卡片
|
||||
*
|
||||
*/
|
||||
import { computed, reactive, getCurrentInstance, onMounted, nextTick } from 'vue';
|
||||
import { computed, getCurrentInstance, nextTick, onMounted } from 'vue';
|
||||
import sheep from '@/sheep';
|
||||
import { fen2yuan, formatSales } from '@/sheep/hooks/useGoods';
|
||||
import { formatStock } from '@/sheep/hooks/useGoods';
|
||||
import {
|
||||
fen2yuan,
|
||||
formatExchange,
|
||||
formatSales,
|
||||
formatStock,
|
||||
getRewardActivityRuleItemDescriptions,
|
||||
} from '@/sheep/hooks/useGoods';
|
||||
import { isArray } from 'lodash-es';
|
||||
|
||||
// 数据
|
||||
const state = reactive({});
|
||||
import { PromotionActivityTypeEnum } from '@/sheep/util/const';
|
||||
|
||||
// 接收参数
|
||||
const props = defineProps({
|
||||
@@ -337,17 +430,29 @@
|
||||
default() {
|
||||
return {
|
||||
// 商品价格
|
||||
price: { show: true },
|
||||
price: {
|
||||
show: true,
|
||||
},
|
||||
// 库存
|
||||
stock: { show: true },
|
||||
stock: {
|
||||
show: true,
|
||||
},
|
||||
// 商品名称
|
||||
name: { show: true },
|
||||
name: {
|
||||
show: true,
|
||||
},
|
||||
// 商品介绍
|
||||
introduction: { show: true },
|
||||
introduction: {
|
||||
show: true,
|
||||
},
|
||||
// 市场价
|
||||
marketPrice: { show: true },
|
||||
marketPrice: {
|
||||
show: true,
|
||||
},
|
||||
// 销量
|
||||
salesCount: { show: true },
|
||||
salesCount: {
|
||||
show: true,
|
||||
},
|
||||
};
|
||||
},
|
||||
},
|
||||
@@ -417,6 +522,17 @@
|
||||
},
|
||||
});
|
||||
|
||||
// 优惠文案
|
||||
const discountText = computed(() => {
|
||||
const promotionType = props.data.promotionType;
|
||||
if (promotionType === 4) {
|
||||
return '限时优惠';
|
||||
} else if (promotionType === 6) {
|
||||
return '会员价';
|
||||
}
|
||||
return undefined;
|
||||
});
|
||||
|
||||
// 组件样式
|
||||
const elStyles = computed(() => {
|
||||
return {
|
||||
@@ -432,10 +548,18 @@
|
||||
const salesAndStock = computed(() => {
|
||||
let text = [];
|
||||
if (props.goodsFields.salesCount?.show) {
|
||||
text.push(formatSales(props.data.sales_show_type, props.data.salesCount));
|
||||
if (props.data.activityType && props.data.activityType === PromotionActivityTypeEnum.POINT.type) {
|
||||
text.push(formatExchange(props.data.sales_show_type, (props.data.pointTotalStock || 0) - (props.data.pointStock || 0)));
|
||||
}else {
|
||||
text.push(formatSales(props.data.sales_show_type, props.data.salesCount));
|
||||
}
|
||||
}
|
||||
if (props.goodsFields.stock?.show) {
|
||||
text.push(formatStock(props.data.stock_show_type, props.data.stock));
|
||||
if (props.data.activityType && props.data.activityType === PromotionActivityTypeEnum.POINT.type) {
|
||||
text.push(formatStock(props.data.stock_show_type, props.data.pointTotalStock));
|
||||
}else {
|
||||
text.push(formatStock(props.data.stock_show_type, props.data.stock));
|
||||
}
|
||||
}
|
||||
return text.join(' | ');
|
||||
});
|
||||
@@ -454,7 +578,10 @@
|
||||
function getGoodsPriceCardWH() {
|
||||
if (props.size === 'md') {
|
||||
const view = uni.createSelectorQuery().in(proxy);
|
||||
view.select(`#${elId}`).fields({ size: true, scrollOffset: true });
|
||||
view.select(`#${elId}`).fields({
|
||||
size: true,
|
||||
scrollOffset: true,
|
||||
});
|
||||
view.exec((data) => {
|
||||
let totalHeight = 0;
|
||||
const goodsPriceCard = data[0];
|
||||
@@ -763,4 +890,33 @@
|
||||
color: #ffffff;
|
||||
}
|
||||
}
|
||||
|
||||
.card {
|
||||
width: fit-content;
|
||||
height: fit-content;
|
||||
padding: 2rpx 10rpx;
|
||||
background-color: red;
|
||||
color: #ffffff;
|
||||
font-size: 24rpx;
|
||||
margin-top: 5rpx;
|
||||
}
|
||||
|
||||
.card2 {
|
||||
width: fit-content;
|
||||
height: fit-content;
|
||||
padding: 2rpx 10rpx;
|
||||
background-color: rgb(255, 242, 241);
|
||||
color: #ff2621;
|
||||
font-size: 24rpx;
|
||||
margin: 5rpx 0 5rpx 5rpx;
|
||||
}
|
||||
|
||||
.iconBox {
|
||||
width: 100%;
|
||||
height: fit-content;
|
||||
margin-top: 10rpx;
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -28,6 +28,14 @@
|
||||
>
|
||||
¥{{ fen2yuan(price) }}
|
||||
</view>
|
||||
<view v-if="point && Number(price) > 0">+</view>
|
||||
<view class="price-text ss-flex ss-col-center" v-if="point">
|
||||
<image
|
||||
:src="sheep.$url.static('/static/img/shop/goods/score1.svg')"
|
||||
class="point-img"
|
||||
></image>
|
||||
<view>{{ point }}</view>
|
||||
</view>
|
||||
<view v-if="num" class="total-text ss-flex ss-col-center">x {{ num }}</view>
|
||||
<slot name="priceSuffix"></slot>
|
||||
</view>
|
||||
@@ -88,7 +96,7 @@
|
||||
type: [String, Number],
|
||||
default: 0,
|
||||
},
|
||||
score: {
|
||||
point: {
|
||||
type: [String, Number],
|
||||
default: '',
|
||||
},
|
||||
@@ -113,7 +121,7 @@
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.score-img {
|
||||
.point-img {
|
||||
width: 36rpx;
|
||||
height: 36rpx;
|
||||
margin: 0 4rpx;
|
||||
|
||||
@@ -0,0 +1,328 @@
|
||||
<!-- 装修商品组件:【积分商城】商品卡片 -->
|
||||
<template>
|
||||
<!-- 商品卡片 -->
|
||||
<view>
|
||||
<!-- 布局1. 单列大图(上图,下内容)-->
|
||||
<view
|
||||
v-if="layoutType === LayoutTypeEnum.ONE_COL_BIG_IMG && state.spuList.length"
|
||||
class="goods-sl-box"
|
||||
>
|
||||
<view
|
||||
class="goods-box"
|
||||
v-for="item in state.spuList"
|
||||
:key="item.id"
|
||||
:style="[{ marginBottom: data.space * 2 + 'rpx' }]"
|
||||
>
|
||||
<s-goods-column
|
||||
class=""
|
||||
size="sl"
|
||||
:goodsFields="data.fields"
|
||||
:tagStyle="data.badge"
|
||||
:data="item"
|
||||
:titleColor="data.fields.name?.color"
|
||||
:subTitleColor="data.fields.introduction.color"
|
||||
:topRadius="data.borderRadiusTop"
|
||||
:bottomRadius="data.borderRadiusBottom"
|
||||
@click="sheep.$router.go('/pages/goods/point', { id: item.activityId })"
|
||||
>
|
||||
<!-- 购买按钮 -->
|
||||
<template v-slot:cart>
|
||||
<button class="ss-reset-button cart-btn" :style="[buyStyle]">
|
||||
{{ btnBuy.type === 'text' ? btnBuy.text : '' }}
|
||||
</button>
|
||||
</template>
|
||||
</s-goods-column>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 布局2. 单列小图(左图,右内容) -->
|
||||
<view
|
||||
v-if="layoutType === LayoutTypeEnum.ONE_COL_SMALL_IMG && state.spuList.length"
|
||||
class="goods-lg-box"
|
||||
>
|
||||
<view
|
||||
class="goods-box"
|
||||
:style="[{ marginBottom: data.space + 'px' }]"
|
||||
v-for="item in state.spuList"
|
||||
:key="item.id"
|
||||
>
|
||||
<s-goods-column
|
||||
class="goods-card"
|
||||
size="lg"
|
||||
:goodsFields="data.fields"
|
||||
:data="item"
|
||||
:tagStyle="data.badge"
|
||||
:titleColor="data.fields.name?.color"
|
||||
:subTitleColor="data.fields.introduction.color"
|
||||
:topRadius="data.borderRadiusTop"
|
||||
:bottomRadius="data.borderRadiusBottom"
|
||||
@tap="sheep.$router.go('/pages/goods/point', { id: item.activityId })"
|
||||
>
|
||||
<!-- 购买按钮 -->
|
||||
<template v-slot:cart>
|
||||
<button class="ss-reset-button cart-btn" :style="[buyStyle]">
|
||||
{{ btnBuy.type === 'text' ? btnBuy.text : '' }}
|
||||
</button>
|
||||
</template>
|
||||
</s-goods-column>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 布局3. 双列(每一列:上图,下内容)-->
|
||||
<view
|
||||
v-if="layoutType === LayoutTypeEnum.TWO_COL && state.spuList.length"
|
||||
class="goods-md-wrap ss-flex ss-flex-wrap ss-col-top"
|
||||
>
|
||||
<view class="goods-list-box">
|
||||
<view
|
||||
class="left-list"
|
||||
:style="[{ paddingRight: data.space + 'rpx', marginBottom: data.space + 'px' }]"
|
||||
v-for="item in state.leftSpuList"
|
||||
:key="item.id"
|
||||
>
|
||||
<s-goods-column
|
||||
class="goods-md-box"
|
||||
size="md"
|
||||
:goodsFields="data.fields"
|
||||
:tagStyle="data.badge"
|
||||
:data="item"
|
||||
:titleColor="data.fields.name?.color"
|
||||
:subTitleColor="data.fields.introduction.color"
|
||||
:topRadius="data.borderRadiusTop"
|
||||
:bottomRadius="data.borderRadiusBottom"
|
||||
:titleWidth="330 - marginLeft - marginRight"
|
||||
@click="sheep.$router.go('/pages/goods/seckill', { id: item.activityId })"
|
||||
@getHeight="calculateGoodsColumn($event, 'left')"
|
||||
>
|
||||
<!-- 购买按钮 -->
|
||||
<template v-slot:cart>
|
||||
<button class="ss-reset-button cart-btn" :style="[buyStyle]">
|
||||
{{ btnBuy.type === 'text' ? btnBuy.text : '' }}
|
||||
</button>
|
||||
</template>
|
||||
</s-goods-column>
|
||||
</view>
|
||||
</view>
|
||||
<view class="goods-list-box">
|
||||
<view
|
||||
class="right-list"
|
||||
:style="[{ paddingLeft: data.space + 'rpx', marginBottom: data.space + 'px' }]"
|
||||
v-for="item in state.rightSpuList"
|
||||
:key="item.id"
|
||||
>
|
||||
<s-goods-column
|
||||
class="goods-md-box"
|
||||
size="md"
|
||||
:goodsFields="data.fields"
|
||||
:tagStyle="data.badge"
|
||||
:data="item"
|
||||
:titleColor="data.fields.name?.color"
|
||||
:subTitleColor="data.fields.introduction.color"
|
||||
:topRadius="data.borderRadiusTop"
|
||||
:bottomRadius="data.borderRadiusBottom"
|
||||
:titleWidth="330 - marginLeft - marginRight"
|
||||
@click="sheep.$router.go('/pages/goods/seckill', { id: item.activityId })"
|
||||
@getHeight="calculateGoodsColumn($event, 'right')"
|
||||
>
|
||||
<!-- 购买按钮 -->
|
||||
<template v-slot:cart>
|
||||
<button class="ss-reset-button cart-btn" :style="[buyStyle]">
|
||||
{{ btnBuy.type === 'text' ? btnBuy.text : '' }}
|
||||
</button>
|
||||
</template>
|
||||
</s-goods-column>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
/**
|
||||
* 商品卡片
|
||||
*/
|
||||
import { computed, onMounted, reactive, ref } from 'vue';
|
||||
import sheep from '@/sheep';
|
||||
import SpuApi from '@/sheep/api/product/spu';
|
||||
import PointApi from '@/sheep/api/promotion/point';
|
||||
import { PromotionActivityTypeEnum } from '@/sheep/util/const';
|
||||
|
||||
// 布局类型
|
||||
const LayoutTypeEnum = {
|
||||
// 单列大图
|
||||
ONE_COL_BIG_IMG: 'oneColBigImg',
|
||||
// 双列
|
||||
TWO_COL: 'twoCol',
|
||||
// 单列小图
|
||||
ONE_COL_SMALL_IMG: 'oneColSmallImg',
|
||||
};
|
||||
|
||||
const state = reactive({
|
||||
spuList: [],
|
||||
leftSpuList: [],
|
||||
rightSpuList: [],
|
||||
});
|
||||
const props = defineProps({
|
||||
data: {
|
||||
type: Object,
|
||||
default() {},
|
||||
},
|
||||
styles: {
|
||||
type: Object,
|
||||
default() {},
|
||||
},
|
||||
});
|
||||
|
||||
const { layoutType, btnBuy, activityIds } = props.data || {};
|
||||
const { marginLeft, marginRight } = props.styles || {};
|
||||
|
||||
// 购买按钮样式
|
||||
const buyStyle = computed(() => {
|
||||
if (btnBuy.type === 'text') {
|
||||
// 文字按钮:线性渐变背景颜色
|
||||
return {
|
||||
background: `linear-gradient(to right, ${btnBuy.bgBeginColor}, ${btnBuy.bgEndColor})`,
|
||||
};
|
||||
}
|
||||
if (btnBuy.type === 'img') {
|
||||
// 图片按钮
|
||||
return {
|
||||
width: '54rpx',
|
||||
height: '54rpx',
|
||||
background: `url(${sheep.$url.cdn(btnBuy.imgUrl)}) no-repeat`,
|
||||
backgroundSize: '100% 100%',
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
//region 商品瀑布流布局
|
||||
// 下一个要处理的商品索引
|
||||
let count = 0;
|
||||
// 左列的高度
|
||||
let leftHeight = 0;
|
||||
// 右列的高度
|
||||
let rightHeight = 0;
|
||||
|
||||
/**
|
||||
* 计算商品在左列还是右列
|
||||
* @param height 商品的高度
|
||||
* @param where 添加到哪一列
|
||||
*/
|
||||
function calculateGoodsColumn(height = 0, where = 'left') {
|
||||
// 处理完
|
||||
if (!state.spuList[count]) return;
|
||||
// 增加列的高度
|
||||
if (where === 'left') leftHeight += height;
|
||||
if (where === 'right') rightHeight += height;
|
||||
// 添加到矮的一列
|
||||
if (leftHeight <= rightHeight) {
|
||||
state.leftSpuList.push(state.spuList[count]);
|
||||
} else {
|
||||
state.rightSpuList.push(state.spuList[count]);
|
||||
}
|
||||
// 计数
|
||||
count++;
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
/**
|
||||
* 根据商品编号列表,获取商品列表
|
||||
* @param ids 商品编号列表
|
||||
* @return {Promise<undefined>} 商品列表
|
||||
*/
|
||||
async function getPointActivityDetailList(ids) {
|
||||
const { data } = await PointApi.getPointActivityListByIds(ids);
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据商品编号,获取商品详情
|
||||
* @param ids 商品编号列表
|
||||
* @return {Promise<undefined>} 商品列表
|
||||
*/
|
||||
async function getSpuDetail(ids) {
|
||||
const { data: spu } = await SpuApi.getSpuDetail(ids);
|
||||
return spu;
|
||||
}
|
||||
|
||||
// 初始化
|
||||
onMounted(async () => {
|
||||
// 加载活动列表
|
||||
const activityList = await getPointActivityDetailList(activityIds.join(','));
|
||||
// 循环获取活动商品SPU详情并添加到spuList
|
||||
for (const activity of activityList) {
|
||||
state.spuList.push(await getSpuDetail(activity.spuId));
|
||||
}
|
||||
|
||||
// 循环活动列表
|
||||
activityList.forEach((activity) => {
|
||||
// 查找对应的 spu 并更新价格
|
||||
const spu = state.spuList.find((spu) => activity.spuId === spu.id);
|
||||
if (spu) {
|
||||
spu.pointStock = activity.stock
|
||||
spu.pointTotalStock = activity.totalStock
|
||||
spu.point = activity.point
|
||||
spu.pointPrice = activity.price
|
||||
// 赋值活动ID,为了点击跳转详情页
|
||||
spu.activityId = activity.id;
|
||||
// 赋值活动类型
|
||||
spu.activityType = PromotionActivityTypeEnum.POINT.type;
|
||||
}
|
||||
});
|
||||
|
||||
// 只有双列布局时需要
|
||||
if (layoutType === LayoutTypeEnum.TWO_COL) {
|
||||
// 分列
|
||||
calculateGoodsColumn();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.goods-md-wrap {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.goods-list-box {
|
||||
width: 50%;
|
||||
box-sizing: border-box;
|
||||
|
||||
.left-list {
|
||||
&:nth-last-child(1) {
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
}
|
||||
|
||||
.right-list {
|
||||
&:nth-last-child(1) {
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.goods-box {
|
||||
&:nth-last-of-type(1) {
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
}
|
||||
|
||||
.goods-md-box,
|
||||
.goods-sl-box,
|
||||
.goods-lg-box {
|
||||
position: relative;
|
||||
|
||||
.cart-btn {
|
||||
position: absolute;
|
||||
bottom: 18rpx;
|
||||
right: 20rpx;
|
||||
z-index: 11;
|
||||
height: 50rpx;
|
||||
line-height: 50rpx;
|
||||
padding: 0 20rpx;
|
||||
border-radius: 25rpx;
|
||||
font-size: 24rpx;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,458 @@
|
||||
<template>
|
||||
<view>
|
||||
<!-- md卡片:竖向,一行放两个,图上内容下 -->
|
||||
<view v-if="size === 'md'" class="md-goods-card ss-flex-col" :style="[elStyles]" @tap="onClick">
|
||||
<image
|
||||
class="md-img-box"
|
||||
:src="sheep.$url.cdn(data.image)"
|
||||
mode="widthFix"
|
||||
@load="calculatePanelHeight"
|
||||
></image>
|
||||
<view
|
||||
class="md-goods-content ss-flex-col ss-row-around ss-p-b-20 ss-p-t-20 ss-p-x-16"
|
||||
:id="elId"
|
||||
>
|
||||
<view
|
||||
v-if="goodsFields.title?.show"
|
||||
class="md-goods-title ss-line-1"
|
||||
:style="[{ color: titleColor, width: titleWidth ? titleWidth + 'rpx' : '' }]"
|
||||
>
|
||||
{{ data.title }}
|
||||
</view>
|
||||
<view
|
||||
v-if="goodsFields.subtitle?.show"
|
||||
class="md-goods-subtitle ss-m-t-16 ss-line-1"
|
||||
:style="[{ color: subTitleColor }]"
|
||||
>
|
||||
{{ data.subtitle }}
|
||||
</view>
|
||||
<view class="ss-col-bottom">
|
||||
<view
|
||||
v-if="goodsFields.score_price?.show"
|
||||
class="md-goods-price ss-m-t-16 font-OPPOSANS ss-m-r-10 ss-flex"
|
||||
:style="[{ color: goodsFields.score_price.color }]"
|
||||
>
|
||||
<view>{{ Number(data.price[0]) > 0 ? '¥' + data.price[0] + '+' : '' }}</view>
|
||||
<image
|
||||
:src="sheep.$url.static('/static/img/shop/goods/score1.svg')"
|
||||
class="score-img"
|
||||
></image>
|
||||
{{ data.score }}
|
||||
</view>
|
||||
|
||||
<view
|
||||
v-if="goodsFields.price?.show && data.original_price > 0"
|
||||
class="goods-origin-price ss-m-t-16 font-OPPOSANS ss-flex"
|
||||
:style="[{ color: goodsFields.price.color }]"
|
||||
>
|
||||
<text class="price-unit ss-font-20">{{ priceUnit }}</text>
|
||||
<view class="ss-m-l-8">{{ data.original_price }}</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="ss-m-t-16 ss-flex ss-col-center ss-flex-wrap">
|
||||
<view class="sales-text">{{ salesAndStock }}</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<slot name="cart">
|
||||
<view class="cart-box ss-flex ss-col-center ss-row-center">
|
||||
<image class="cart-icon" src="/static/img/shop/tabbar/category2.png" mode=""></image>
|
||||
</view>
|
||||
</slot>
|
||||
</view>
|
||||
<!-- lg卡片:横向型,一行放一个,图片左内容右边 -->
|
||||
<view
|
||||
v-if="size === 'lg'"
|
||||
class="lg-goods-card ss-flex ss-col-stretch"
|
||||
:style="[elStyles]"
|
||||
@tap="onClick"
|
||||
>
|
||||
<image class="lg-img-box" :src="sheep.$url.cdn(data.image)" mode="aspectFill"></image>
|
||||
<view class="lg-goods-content ss-flex-1 ss-flex-col ss-row-between ss-p-b-10 ss-p-t-20">
|
||||
<view class="ss-m-r-20">
|
||||
<view
|
||||
v-if="goodsFields.title?.show"
|
||||
class="lg-goods-title ss-line-2"
|
||||
:style="[{ color: titleColor }]"
|
||||
>
|
||||
{{ data.title }}
|
||||
</view>
|
||||
<view
|
||||
v-if="goodsFields.subtitle?.show"
|
||||
class="lg-goods-subtitle ss-m-t-10 ss-line-1"
|
||||
:style="[{ color: subTitleColor }]"
|
||||
>
|
||||
{{ data.subtitle }}
|
||||
</view>
|
||||
</view>
|
||||
<view>
|
||||
<view class="ss-m-t-10">
|
||||
<view
|
||||
v-if="goodsFields.score_price?.show"
|
||||
class="lg-goods-price ss-m-r-12 ss-flex ss-col-bottom font-OPPOSANS"
|
||||
:style="[{ color: goodsFields.score_price.color }]"
|
||||
>
|
||||
<view>{{ Number(data.price[0]) > 0 ? '¥' + data.price[0] + '+' : '' }}</view>
|
||||
<image
|
||||
:src="sheep.$url.static('/static/img/shop/goods/score1.svg')"
|
||||
class="score-img"
|
||||
></image>
|
||||
{{ data.score }}
|
||||
</view>
|
||||
<view
|
||||
v-if="goodsFields.price?.show && data.original_price > 0"
|
||||
class="goods-origin-price ss-flex ss-col-bottom font-OPPOSANS"
|
||||
:style="[{ color: goodsFields.price.color }]"
|
||||
>
|
||||
<text class="price-unit ss-font-20">{{ priceUnit }}</text>
|
||||
<view class="ss-m-l-8">{{ data.original_price }}</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="ss-m-t-16 ss-flex ss-col-center ss-flex-wrap">
|
||||
<view class="sales-text">{{ salesAndStock }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<slot name="cart"
|
||||
><view class="buy-box ss-flex ss-col-center ss-row-center">去兑换</view></slot
|
||||
>
|
||||
</view>
|
||||
<!-- sl卡片:竖向型,一行放一个,图片上内容下边 -->
|
||||
<view v-if="size === 'sl'" class="sl-goods-card ss-flex-col" @tap="onClick">
|
||||
<image class="sl-img-box" :src="sheep.$url.cdn(data.image)" mode="aspectFill"></image>
|
||||
|
||||
<view class="sl-goods-content ss-flex-col ss-row-between ss-p-b-20 ss-p-t-20">
|
||||
<view class="ss-m-b-20">
|
||||
<view class="sl-goods-title ss-line-1 ss-p-l-16 ss-p-r-16">
|
||||
{{ data.title }}
|
||||
</view>
|
||||
<view v-if="data.subtitle" class="sl-goods-subtitle ss-p-l-16 ss-p-r-16 ss-m-t-16">
|
||||
{{ data.subtitle }}
|
||||
</view>
|
||||
</view>
|
||||
<view>
|
||||
<slot name="activity">
|
||||
<view
|
||||
v-if="data.promos?.length"
|
||||
class="tag-box ss-flex ss-col-center ss-flex-wrap ss-p-l-16 ss-p-r-16"
|
||||
>
|
||||
<view
|
||||
class="activity-tag ss-m-r-10 ss-m-t-16"
|
||||
v-for="item in data.promos"
|
||||
:key="item.id"
|
||||
>
|
||||
{{ item.title }}
|
||||
</view>
|
||||
</view>
|
||||
</slot>
|
||||
<view class="ss-flex ss-col-bottom ss-p-l-16 ss-p-r-16 font-OPPOSANS">
|
||||
<view class="sl-goods-price ss-m-r-12 ss-flex">
|
||||
<view>{{ Number(data.price[0]) > 0 ? '¥' + data.price[0] + '+' : '' }}</view>
|
||||
<image
|
||||
:src="sheep.$url.static('/static/img/shop/goods/score1.svg')"
|
||||
class="score-img"
|
||||
></image>
|
||||
<view>{{ data.score ? data.score : '' }}</view>
|
||||
</view>
|
||||
<view
|
||||
v-if="data.original_price > 0"
|
||||
class="goods-origin-price ss-m-t-16 font-OPPOSANS ss-flex"
|
||||
>
|
||||
<text class="price-unit ss-font-20">¥</text>
|
||||
<view class="ss-m-l-8">{{ data.original_price }}</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="ss-p-l-16 ss-p-r-16 ss-m-t-16 ss-flex ss-flex-wrap">
|
||||
<view class="sales-text">{{ salesAndStock }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<slot name="cart"
|
||||
><view class="buy-box ss-flex ss-col-center ss-row-center">去兑换</view></slot
|
||||
>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
import { computed, getCurrentInstance } from 'vue';
|
||||
import sheep from '@/sheep';
|
||||
import { formatSales } from '@/sheep/hooks/useGoods';
|
||||
import { formatStock } from '@/sheep/hooks/useGoods';
|
||||
/**
|
||||
* 订单卡片
|
||||
*
|
||||
* @property {String} img - 图片
|
||||
* @property {String} title - 标题
|
||||
* @property {Number} titleWidth = 0 - 标题宽度,默认0,单位rpx
|
||||
* @property {String} skuText - 规格
|
||||
* @property {String | Number} score - 积分
|
||||
* @property {String | Number} price - 价格
|
||||
* @property {String | Number} originalPrice - 单购价
|
||||
* @property {String} priceColor - 价格颜色
|
||||
* @property {Number | String} num - 数量
|
||||
*
|
||||
*/
|
||||
const props = defineProps({
|
||||
goodsFields: {
|
||||
type: [Array, Object],
|
||||
default() {
|
||||
return {
|
||||
title: { show: true },
|
||||
subtitle: { show: true },
|
||||
price: { show: true },
|
||||
original_price: { show: true },
|
||||
sales: { show: true },
|
||||
stock: { show: true },
|
||||
};
|
||||
},
|
||||
},
|
||||
tagStyle: {
|
||||
type: Object,
|
||||
default: {},
|
||||
},
|
||||
data: {
|
||||
type: Object,
|
||||
default: {},
|
||||
},
|
||||
size: {
|
||||
type: String,
|
||||
default: 'sl',
|
||||
},
|
||||
background: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
topRadius: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
bottomRadius: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
titleWidth: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
titleColor: {
|
||||
type: String,
|
||||
default: '#333',
|
||||
},
|
||||
priceUnit: {
|
||||
type: String,
|
||||
default: '¥',
|
||||
},
|
||||
subTitleColor: {
|
||||
type: String,
|
||||
default: '#999999',
|
||||
},
|
||||
});
|
||||
// 组件样式
|
||||
const elStyles = computed(() => {
|
||||
return {
|
||||
background: props.background,
|
||||
'border-top-left-radius': props.topRadius + 'px',
|
||||
'border-top-right-radius': props.topRadius + 'px',
|
||||
'border-bottom-left-radius': props.bottomRadius + 'px',
|
||||
'border-bottom-right-radius': props.bottomRadius + 'px',
|
||||
};
|
||||
});
|
||||
const emits = defineEmits(['click', 'getHeight']);
|
||||
const onClick = () => {
|
||||
emits('click');
|
||||
};
|
||||
// 格式化销量、库存信息
|
||||
const salesAndStock = computed(() => {
|
||||
let text = [];
|
||||
text.push(formatSales(props.data.sales_show_type, props.data.sales));
|
||||
text.push(formatStock(props.data.stock_show_type, props.data.stock));
|
||||
return text.join(' | ');
|
||||
});
|
||||
// 获取实时卡片高度
|
||||
const { proxy } = getCurrentInstance();
|
||||
const elId = `sheep_${Math.ceil(Math.random() * 10e5).toString(36)}`;
|
||||
function calculatePanelHeight(e) {
|
||||
if (props.size === 'md') {
|
||||
const view = uni.createSelectorQuery().in(proxy);
|
||||
view.select(`#${elId}`).fields({ size: true, scrollOffset: true });
|
||||
view.exec((data) => {
|
||||
const goodsPriceCard = data[0];
|
||||
const card = {
|
||||
width: goodsPriceCard.width,
|
||||
height: (goodsPriceCard.width / e.detail.width) * e.detail.height + goodsPriceCard.height,
|
||||
};
|
||||
emits('getHeight', card.height);
|
||||
});
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.price-unit {
|
||||
margin-right: -4px;
|
||||
}
|
||||
.sales-text {
|
||||
display: table;
|
||||
font-size: 24rpx;
|
||||
transform: scale(0.8);
|
||||
margin-left: -16rpx;
|
||||
color: #c4c4c4;
|
||||
}
|
||||
|
||||
// md
|
||||
.md-goods-card {
|
||||
overflow: hidden;
|
||||
width: 100%;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
background-color: $white;
|
||||
position: relative;
|
||||
|
||||
.md-img-box {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.md-goods-title {
|
||||
font-size: 26rpx;
|
||||
color: #333;
|
||||
width: 100%;
|
||||
}
|
||||
.md-goods-subtitle {
|
||||
font-size: 24rpx;
|
||||
font-weight: 400;
|
||||
color: #999999;
|
||||
}
|
||||
|
||||
.md-goods-price {
|
||||
font-size: 30rpx;
|
||||
color: $red;
|
||||
line-height: 36rpx;
|
||||
}
|
||||
|
||||
.cart-box {
|
||||
width: 54rpx;
|
||||
height: 54rpx;
|
||||
background: linear-gradient(90deg, #fe8900, #ff5e00);
|
||||
border-radius: 50%;
|
||||
position: absolute;
|
||||
bottom: 50rpx;
|
||||
right: 20rpx;
|
||||
z-index: 2;
|
||||
|
||||
.cart-icon {
|
||||
width: 30rpx;
|
||||
height: 30rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// lg
|
||||
.lg-goods-card {
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
background-color: $white;
|
||||
height: 280rpx;
|
||||
|
||||
.lg-img-box {
|
||||
width: 280rpx;
|
||||
height: 280rpx;
|
||||
margin-right: 20rpx;
|
||||
}
|
||||
|
||||
.lg-goods-title {
|
||||
font-size: 28rpx;
|
||||
font-weight: 500;
|
||||
color: #333333;
|
||||
// line-height: 36rpx;
|
||||
// width: 410rpx;
|
||||
}
|
||||
.lg-goods-subtitle {
|
||||
font-size: 24rpx;
|
||||
font-weight: 400;
|
||||
color: #999999;
|
||||
line-height: 30rpx;
|
||||
// width: 410rpx;
|
||||
}
|
||||
|
||||
.lg-goods-price {
|
||||
font-size: 30rpx;
|
||||
color: $red;
|
||||
line-height: 36rpx;
|
||||
}
|
||||
|
||||
.buy-box {
|
||||
position: absolute;
|
||||
bottom: 20rpx;
|
||||
right: 20rpx;
|
||||
z-index: 2;
|
||||
width: 120rpx;
|
||||
height: 50rpx;
|
||||
background: linear-gradient(90deg, var(--ui-BG-Main), var(--ui-BG-Main-gradient));
|
||||
border-radius: 25rpx;
|
||||
font-size: 24rpx;
|
||||
color: #ffffff;
|
||||
}
|
||||
.tag-box {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
.sl-goods-card {
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
width: 100%;
|
||||
background-color: $white;
|
||||
|
||||
.sl-img-box {
|
||||
width: 100%;
|
||||
height: 360rpx;
|
||||
}
|
||||
|
||||
.sl-goods-title {
|
||||
font-size: 26rpx;
|
||||
color: #333;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.sl-goods-subtitle {
|
||||
font-size: 24rpx;
|
||||
font-weight: 400;
|
||||
color: #999999;
|
||||
line-height: 30rpx;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.sl-goods-price {
|
||||
font-size: 30rpx;
|
||||
color: $red;
|
||||
}
|
||||
|
||||
.buy-box {
|
||||
position: absolute;
|
||||
bottom: 20rpx;
|
||||
right: 20rpx;
|
||||
z-index: 2;
|
||||
width: 148rpx;
|
||||
height: 50rpx;
|
||||
background: linear-gradient(90deg, #fe8900, #ff5e00);
|
||||
border-radius: 25rpx;
|
||||
font-size: 24rpx;
|
||||
color: #ffffff;
|
||||
}
|
||||
}
|
||||
.goods-origin-price {
|
||||
font-size: 20rpx;
|
||||
color: #c4c4c4;
|
||||
text-decoration: line-through;
|
||||
}
|
||||
.score-img {
|
||||
width: 36rpx;
|
||||
height: 36rpx;
|
||||
margin: 0 4rpx;
|
||||
}
|
||||
</style>
|
||||
@@ -19,8 +19,11 @@
|
||||
<view class="goods-title ss-line-2">{{ state.goodsInfo.name }}</view>
|
||||
<view class="header-right-bottom ss-flex ss-col-center ss-row-between">
|
||||
<!-- 价格 -->
|
||||
<view class="price-text">
|
||||
{{ fen2yuan(state.selectedSku.price || state.goodsInfo.price) }}
|
||||
<view v-if="state.goodsInfo.activity_type === PromotionActivityTypeEnum.POINT.type" class="price-text">
|
||||
{{ getShowPriceText }}
|
||||
</view>
|
||||
<view v-else class="price-text">
|
||||
¥{{ fen2yuan(state.selectedSku.price || state.goodsInfo.price) }}
|
||||
</view>
|
||||
<!-- 秒杀价格标签 -->
|
||||
<view class="tig ss-flex ss-col-center">
|
||||
@@ -92,12 +95,15 @@
|
||||
import { computed, reactive, watch } from 'vue';
|
||||
import sheep from '@/sheep';
|
||||
import { convertProductPropertyList, fen2yuan } from '@/sheep/hooks/useGoods';
|
||||
import { min } from 'lodash-es';
|
||||
import { isEmpty, min } from 'lodash-es';
|
||||
import { PromotionActivityTypeEnum } from '@/sheep/util/const';
|
||||
|
||||
const emits = defineEmits(['change', 'addCart', 'buy', 'close']);
|
||||
const props = defineProps({
|
||||
modelValue: {
|
||||
type: Object,
|
||||
default() {},
|
||||
default() {
|
||||
},
|
||||
},
|
||||
show: {
|
||||
type: Boolean,
|
||||
@@ -114,7 +120,14 @@
|
||||
selectedSku: {},
|
||||
currentPropertyArray: [],
|
||||
});
|
||||
|
||||
const getShowPriceText = computed(() => {
|
||||
let priceText = `¥${fen2yuan(state.goodsInfo.price)}`;
|
||||
if (!isEmpty(state.selectedSku)) {
|
||||
const sku = state.selectedSku;
|
||||
priceText = `${sku.point}积分${!sku.pointPrice ? '' : `+¥${fen2yuan(sku.pointPrice)}`}`;
|
||||
}
|
||||
return priceText;
|
||||
});
|
||||
const propertyList = convertProductPropertyList(state.goodsInfo.skus);
|
||||
// SKU 列表
|
||||
const skuList = computed(() => {
|
||||
@@ -344,11 +357,6 @@
|
||||
font-weight: 500;
|
||||
color: $red;
|
||||
font-family: OPPOSANS;
|
||||
|
||||
&::before {
|
||||
content: '¥';
|
||||
font-size: 24rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.stock-text {
|
||||
|
||||
@@ -1,106 +1,139 @@
|
||||
<template>
|
||||
<!-- 规格弹窗 -->
|
||||
<su-popup :show="show" round="10" @close="emits('close')">
|
||||
<!-- 规格弹窗 -->
|
||||
<su-popup :show="show" round="10" @close="emits('close')">
|
||||
<!-- SKU 信息 -->
|
||||
<view class="ss-modal-box bg-white ss-flex-col">
|
||||
<view class="modal-header ss-flex ss-col-center">
|
||||
<view class="header-left ss-m-r-30">
|
||||
<image class="sku-image" :src="state.selectedSku.picUrl || goodsInfo.picUrl" mode="aspectFill" />
|
||||
</view>
|
||||
<view class="header-right ss-flex-col ss-row-between ss-flex-1">
|
||||
<view class="goods-title ss-line-2">{{ goodsInfo.name }}</view>
|
||||
<view class="header-right-bottom ss-flex ss-col-center ss-row-between">
|
||||
<view class="ss-flex">
|
||||
<view class="price-text">
|
||||
{{ fen2yuan( state.selectedSku.price || goodsInfo.price) }}
|
||||
</view>
|
||||
</view>
|
||||
<view class="stock-text ss-m-l-20">
|
||||
{{ formatStock('exact', state.selectedSku.stock || goodsInfo.stock) }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="ss-modal-box bg-white ss-flex-col">
|
||||
<view class="modal-header ss-flex ss-col-center">
|
||||
<view class="header-left ss-m-r-30">
|
||||
<image
|
||||
class="sku-image"
|
||||
:src="state.selectedSku.picUrl || goodsInfo.picUrl"
|
||||
mode="aspectFill"
|
||||
/>
|
||||
</view>
|
||||
<view class="header-right ss-flex-col ss-row-between ss-flex-1">
|
||||
<view class="goods-title ss-line-2">{{ goodsInfo.name }}</view>
|
||||
<view class="header-right-bottom ss-flex ss-col-center ss-row-between">
|
||||
<view class="ss-flex">
|
||||
<view class="price-text">
|
||||
{{
|
||||
fen2yuan(
|
||||
state.selectedSku.promotionPrice || state.selectedSku.price || goodsInfo.price,
|
||||
)
|
||||
}}
|
||||
<text v-if="state.selectedSku.promotionType > 0">
|
||||
<text class="iconBox" v-if="state.selectedSku.promotionType === 4">
|
||||
限时优惠
|
||||
</text>
|
||||
<text class="iconBox" v-else-if="state.selectedSku.promotionType === 6">
|
||||
会员价
|
||||
</text>
|
||||
<text class="origin-price-text">
|
||||
{{ fen2yuan(state.selectedSku.price) }}
|
||||
</text>
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="stock-text ss-m-l-20">
|
||||
{{ formatStock('exact', state.selectedSku.stock || goodsInfo.stock) }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 属性选择 -->
|
||||
<view class="modal-content ss-flex-1">
|
||||
<scroll-view scroll-y="true" class="modal-content-scroll" @touchmove.stop>
|
||||
<view class="sku-item ss-m-b-20" v-for="property in propertyList" :key="property.id">
|
||||
<view class="label-text ss-m-b-20">{{ property.name }}</view>
|
||||
<view class="ss-flex ss-col-center ss-flex-wrap">
|
||||
<button class="ss-reset-button spec-btn" v-for="value in property.values" :class="[
|
||||
<view class="modal-content ss-flex-1">
|
||||
<scroll-view scroll-y="true" class="modal-content-scroll" @touchmove.stop>
|
||||
<view class="sku-item ss-m-b-20" v-for="property in propertyList" :key="property.id">
|
||||
<view class="label-text ss-m-b-20">{{ property.name }}</view>
|
||||
<view class="ss-flex ss-col-center ss-flex-wrap">
|
||||
<button
|
||||
class="ss-reset-button spec-btn"
|
||||
v-for="value in property.values"
|
||||
:class="[
|
||||
{
|
||||
'ui-BG-Main-Gradient': state.currentPropertyArray[property.id] === value.id,
|
||||
},
|
||||
{
|
||||
'disabled-btn': value.disabled === true,
|
||||
},
|
||||
]" :key="value.id" :disabled="value.disabled === true" @tap="onSelectSku(property.id, value.id)">
|
||||
{{ value.name }}
|
||||
</button>
|
||||
</view>
|
||||
</view>
|
||||
<view class="buy-num-box ss-flex ss-col-center ss-row-between ss-m-b-40">
|
||||
<view class="label-text">购买数量</view>
|
||||
<su-number-box :min="1" :max="state.selectedSku.stock" :step="1"
|
||||
v-model="state.selectedSku.goods_num" @change="onNumberChange($event)" />
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
]"
|
||||
:key="value.id"
|
||||
:disabled="value.disabled === true"
|
||||
@tap="onSelectSku(property.id, value.id)"
|
||||
>
|
||||
{{ value.name }}
|
||||
</button>
|
||||
</view>
|
||||
</view>
|
||||
<view class="buy-num-box ss-flex ss-col-center ss-row-between ss-m-b-40">
|
||||
<view class="label-text">购买数量</view>
|
||||
<su-number-box
|
||||
:min="1"
|
||||
:max="state.selectedSku.stock"
|
||||
:step="1"
|
||||
v-model="state.selectedSku.goods_num"
|
||||
@change="onNumberChange($event)"
|
||||
/>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
|
||||
<!-- 操作区 -->
|
||||
<view class="modal-footer border-top">
|
||||
<view class="buy-box ss-flex ss-col-center ss-flex ss-col-center ss-row-center">
|
||||
<button class="ss-reset-button add-btn ui-Shadow-Main" @tap="onAddCart">加入购物车</button>
|
||||
<button class="ss-reset-button buy-btn ui-Shadow-Main" @tap="onBuy">立即购买</button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</su-popup>
|
||||
<view class="modal-footer border-top">
|
||||
<view class="buy-box ss-flex ss-col-center ss-flex ss-col-center ss-row-center">
|
||||
<button class="ss-reset-button add-btn ui-Shadow-Main" @tap="onAddCart"
|
||||
>加入购物车</button
|
||||
>
|
||||
<button class="ss-reset-button buy-btn ui-Shadow-Main" @tap="onBuy">立即购买</button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</su-popup>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed, reactive, watch } from 'vue';
|
||||
import sheep from '@/sheep';
|
||||
import { computed, reactive, watch } from 'vue';
|
||||
import sheep from '@/sheep';
|
||||
import { formatStock, convertProductPropertyList, fen2yuan } from '@/sheep/hooks/useGoods';
|
||||
|
||||
const emits = defineEmits(['change', 'addCart', 'buy', 'close']);
|
||||
const props = defineProps({
|
||||
goodsInfo: {
|
||||
type: Object,
|
||||
default () {},
|
||||
},
|
||||
show: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
}
|
||||
});
|
||||
const emits = defineEmits(['change', 'addCart', 'buy', 'close']);
|
||||
const props = defineProps({
|
||||
goodsInfo: {
|
||||
type: Object,
|
||||
default() {},
|
||||
},
|
||||
show: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
});
|
||||
|
||||
const state = reactive({
|
||||
selectedSku: {}, // 选中的 SKU
|
||||
currentPropertyArray: [], // 当前选中的属性,实际是个 Map。key 是 property 编号,value 是 value 编号
|
||||
});
|
||||
const state = reactive({
|
||||
selectedSku: {}, // 选中的 SKU
|
||||
currentPropertyArray: [], // 当前选中的属性,实际是个 Map。key 是 property 编号,value 是 value 编号
|
||||
});
|
||||
|
||||
const propertyList = convertProductPropertyList(props.goodsInfo.skus);
|
||||
|
||||
// SKU 列表
|
||||
const skuList = computed(() => {
|
||||
let skuPrices = props.goodsInfo.skus;
|
||||
const propertyList = convertProductPropertyList(props.goodsInfo.skus);
|
||||
// SKU 列表
|
||||
const skuList = computed(() => {
|
||||
let skuPrices = props.goodsInfo.skus;
|
||||
for (let price of skuPrices) {
|
||||
price.value_id_array = price.properties.map((item) => item.valueId)
|
||||
price.value_id_array = price.properties.map((item) => item.valueId);
|
||||
}
|
||||
return skuPrices;
|
||||
});
|
||||
return skuPrices;
|
||||
});
|
||||
|
||||
watch(
|
||||
() => state.selectedSku,
|
||||
(newVal) => {
|
||||
emits('change', newVal);
|
||||
}, {
|
||||
immediate: true, // 立即执行
|
||||
deep: true, // 深度监听
|
||||
},
|
||||
);
|
||||
watch(
|
||||
() => state.selectedSku,
|
||||
(newVal) => {
|
||||
emits('change', newVal);
|
||||
},
|
||||
{
|
||||
immediate: true, // 立即执行
|
||||
deep: true, // 深度监听
|
||||
},
|
||||
);
|
||||
|
||||
// 输入框改变数量
|
||||
function onNumberChange(e) {
|
||||
@@ -110,21 +143,21 @@
|
||||
}
|
||||
|
||||
// 加入购物车
|
||||
function onAddCart() {
|
||||
if (state.selectedSku.id <= 0) {
|
||||
function onAddCart() {
|
||||
if (state.selectedSku.id <= 0) {
|
||||
sheep.$helper.toast('请选择规格');
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (state.selectedSku.stock <= 0) {
|
||||
sheep.$helper.toast('库存不足');
|
||||
return;
|
||||
}
|
||||
|
||||
emits('addCart', state.selectedSku);
|
||||
}
|
||||
}
|
||||
|
||||
// 立即购买
|
||||
function onBuy() {
|
||||
function onBuy() {
|
||||
if (state.selectedSku.id <= 0) {
|
||||
sheep.$helper.toast('请选择规格');
|
||||
return;
|
||||
@@ -134,273 +167,298 @@
|
||||
return;
|
||||
}
|
||||
emits('buy', state.selectedSku);
|
||||
}
|
||||
}
|
||||
|
||||
// 改变禁用状态:计算每个 property 属性值的按钮,是否禁用
|
||||
function changeDisabled(isChecked = false, propertyId = 0, valueId = 0) {
|
||||
// 改变禁用状态:计算每个 property 属性值的按钮,是否禁用
|
||||
function changeDisabled(isChecked = false, propertyId = 0, valueId = 0) {
|
||||
let newSkus = []; // 所有可以选择的 sku 数组
|
||||
if (isChecked) {
|
||||
// 情况一:选中 property
|
||||
// 获得当前点击选中 property 的、所有可用 SKU
|
||||
for (let price of skuList.value) {
|
||||
if (price.stock <= 0) {
|
||||
continue;
|
||||
}
|
||||
if (price.value_id_array.indexOf(valueId) >= 0) {
|
||||
newSkus.push(price);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 情况二:取消选中 property
|
||||
// 当前所选 property 下,所有可以选择的 SKU
|
||||
newSkus = getCanUseSkuList();
|
||||
}
|
||||
if (isChecked) {
|
||||
// 情况一:选中 property
|
||||
// 获得当前点击选中 property 的、所有可用 SKU
|
||||
for (let price of skuList.value) {
|
||||
if (price.stock <= 0) {
|
||||
continue;
|
||||
}
|
||||
if (price.value_id_array.indexOf(valueId) >= 0) {
|
||||
newSkus.push(price);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 情况二:取消选中 property
|
||||
// 当前所选 property 下,所有可以选择的 SKU
|
||||
newSkus = getCanUseSkuList();
|
||||
}
|
||||
|
||||
// 所有存在并且有库存未选择的 SKU 的 value 属性值 id
|
||||
let noChooseValueIds = [];
|
||||
for (let price of newSkus) {
|
||||
noChooseValueIds = noChooseValueIds.concat(price.value_id_array);
|
||||
}
|
||||
noChooseValueIds = Array.from(new Set(noChooseValueIds)); // 去重
|
||||
// 所有存在并且有库存未选择的 SKU 的 value 属性值 id
|
||||
let noChooseValueIds = [];
|
||||
for (let price of newSkus) {
|
||||
noChooseValueIds = noChooseValueIds.concat(price.value_id_array);
|
||||
}
|
||||
noChooseValueIds = Array.from(new Set(noChooseValueIds)); // 去重
|
||||
|
||||
if (isChecked) {
|
||||
// 去除当前选中的 value 属性值 id
|
||||
let index = noChooseValueIds.indexOf(valueId);
|
||||
noChooseValueIds.splice(index, 1);
|
||||
} else {
|
||||
// 循环去除当前已选择的 value 属性值 id
|
||||
state.currentPropertyArray.forEach((currentPropertyId) => {
|
||||
if (currentPropertyId.toString() !== '') {
|
||||
if (isChecked) {
|
||||
// 去除当前选中的 value 属性值 id
|
||||
let index = noChooseValueIds.indexOf(valueId);
|
||||
noChooseValueIds.splice(index, 1);
|
||||
} else {
|
||||
// 循环去除当前已选择的 value 属性值 id
|
||||
state.currentPropertyArray.forEach((currentPropertyId) => {
|
||||
if (currentPropertyId.toString() !== '') {
|
||||
return;
|
||||
}
|
||||
}
|
||||
// currentPropertyId 为空是反选 填充的
|
||||
let index = noChooseValueIds.indexOf(currentPropertyId);
|
||||
if (index >= 0) {
|
||||
// currentPropertyId 存在于 noChooseValueIds
|
||||
noChooseValueIds.splice(index, 1);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 当前已选择的 property 数组
|
||||
let choosePropertyIds = [];
|
||||
if (!isChecked) {
|
||||
// 当前已选择的 property
|
||||
state.currentPropertyArray.forEach((currentPropertyId, currentValueId) => {
|
||||
if (currentPropertyId !== '') {
|
||||
// currentPropertyId 为空是反选 填充的
|
||||
choosePropertyIds.push(currentValueId);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// 当前点击选择的 property
|
||||
choosePropertyIds = [propertyId];
|
||||
}
|
||||
let choosePropertyIds = [];
|
||||
if (!isChecked) {
|
||||
// 当前已选择的 property
|
||||
state.currentPropertyArray.forEach((currentPropertyId, currentValueId) => {
|
||||
if (currentPropertyId !== '') {
|
||||
// currentPropertyId 为空是反选 填充的
|
||||
choosePropertyIds.push(currentValueId);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// 当前点击选择的 property
|
||||
choosePropertyIds = [propertyId];
|
||||
}
|
||||
|
||||
for (let propertyIndex in propertyList) {
|
||||
// 当前点击的 property、或者取消选择时候,已选中的 property 不进行处理
|
||||
if (choosePropertyIds.indexOf(propertyList[propertyIndex]['id']) >= 0) {
|
||||
continue;
|
||||
}
|
||||
// 当前点击的 property、或者取消选择时候,已选中的 property 不进行处理
|
||||
if (choosePropertyIds.indexOf(propertyList[propertyIndex]['id']) >= 0) {
|
||||
continue;
|
||||
}
|
||||
// 如果当前 property id 不存在于有库存的 SKU 中,则禁用
|
||||
for (let valueIndex in propertyList[propertyIndex]['values']) {
|
||||
propertyList[propertyIndex]['values'][valueIndex]['disabled'] =
|
||||
propertyList[propertyIndex]['values'][valueIndex]['disabled'] =
|
||||
noChooseValueIds.indexOf(propertyList[propertyIndex]['values'][valueIndex]['id']) < 0; // true 禁用 or false 不禁用
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 当前所选属性下,获取所有有库存的 SKU 们
|
||||
function getCanUseSkuList() {
|
||||
let newSkus = [];
|
||||
for (let sku of skuList.value) {
|
||||
if (sku.stock <= 0) {
|
||||
continue;
|
||||
}
|
||||
// 当前所选属性下,获取所有有库存的 SKU 们
|
||||
function getCanUseSkuList() {
|
||||
let newSkus = [];
|
||||
for (let sku of skuList.value) {
|
||||
if (sku.stock <= 0) {
|
||||
continue;
|
||||
}
|
||||
let isOk = true;
|
||||
state.currentPropertyArray.forEach((propertyId) => {
|
||||
// propertyId 不为空,并且,这个 条 sku 没有被选中,则排除
|
||||
if (propertyId.toString() !== '' && sku.value_id_array.indexOf(propertyId) < 0) {
|
||||
isOk = false;
|
||||
}
|
||||
});
|
||||
if (isOk) {
|
||||
newSkus.push(sku);
|
||||
}
|
||||
}
|
||||
return newSkus;
|
||||
}
|
||||
// propertyId 不为空,并且,这个 条 sku 没有被选中,则排除
|
||||
if (propertyId.toString() !== '' && sku.value_id_array.indexOf(propertyId) < 0) {
|
||||
isOk = false;
|
||||
}
|
||||
});
|
||||
if (isOk) {
|
||||
newSkus.push(sku);
|
||||
}
|
||||
}
|
||||
return newSkus;
|
||||
}
|
||||
|
||||
// 选择规格
|
||||
function onSelectSku(propertyId, valueId) {
|
||||
// 清空已选择
|
||||
let isChecked = true; // 选中 or 取消选中
|
||||
if (state.currentPropertyArray[propertyId] !== undefined && state.currentPropertyArray[propertyId] === valueId) {
|
||||
// 点击已被选中的,删除并填充 ''
|
||||
isChecked = false;
|
||||
state.currentPropertyArray.splice(propertyId, 1, '');
|
||||
} else {
|
||||
// 选中
|
||||
state.currentPropertyArray[propertyId] = valueId;
|
||||
}
|
||||
// 选择规格
|
||||
function onSelectSku(propertyId, valueId) {
|
||||
// 清空已选择
|
||||
let isChecked = true; // 选中 or 取消选中
|
||||
if (
|
||||
state.currentPropertyArray[propertyId] !== undefined &&
|
||||
state.currentPropertyArray[propertyId] === valueId
|
||||
) {
|
||||
// 点击已被选中的,删除并填充 ''
|
||||
isChecked = false;
|
||||
state.currentPropertyArray.splice(propertyId, 1, '');
|
||||
} else {
|
||||
// 选中
|
||||
state.currentPropertyArray[propertyId] = valueId;
|
||||
}
|
||||
|
||||
// 选中的 property 大类
|
||||
let choosePropertyId = [];
|
||||
state.currentPropertyArray.forEach((currentPropertyId) => {
|
||||
if (currentPropertyId !== '') {
|
||||
// currentPropertyId 为空是反选 填充的
|
||||
choosePropertyId.push(currentPropertyId);
|
||||
}
|
||||
});
|
||||
let choosePropertyId = [];
|
||||
state.currentPropertyArray.forEach((currentPropertyId) => {
|
||||
if (currentPropertyId !== '') {
|
||||
// currentPropertyId 为空是反选 填充的
|
||||
choosePropertyId.push(currentPropertyId);
|
||||
}
|
||||
});
|
||||
|
||||
// 当前所选 property 下,所有可以选择的 SKU 们
|
||||
let newSkuList = getCanUseSkuList();
|
||||
// 当前所选 property 下,所有可以选择的 SKU 们
|
||||
let newSkuList = getCanUseSkuList();
|
||||
|
||||
// 判断所有 property 大类是否选择完成
|
||||
if (choosePropertyId.length === propertyList.length && newSkuList.length) {
|
||||
newSkuList[0].goods_num = state.selectedSku.goods_num || 1;
|
||||
state.selectedSku = newSkuList[0];
|
||||
} else {
|
||||
state.selectedSku = {};
|
||||
}
|
||||
// 判断所有 property 大类是否选择完成
|
||||
if (choosePropertyId.length === propertyList.length && newSkuList.length) {
|
||||
newSkuList[0].goods_num = state.selectedSku.goods_num || 1;
|
||||
state.selectedSku = newSkuList[0];
|
||||
} else {
|
||||
state.selectedSku = {};
|
||||
}
|
||||
|
||||
// 改变 property 禁用状态
|
||||
changeDisabled(isChecked, propertyId, valueId);
|
||||
}
|
||||
// 改变 property 禁用状态
|
||||
changeDisabled(isChecked, propertyId, valueId);
|
||||
}
|
||||
|
||||
changeDisabled(false);
|
||||
changeDisabled(false);
|
||||
// TODO 芋艿:待讨论的优化点:1)单规格,要不要默认选中;2)默认要不要选中第一个规格
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
// 购买
|
||||
.buy-box {
|
||||
padding: 10rpx 0;
|
||||
// 购买
|
||||
.buy-box {
|
||||
padding: 10rpx 0;
|
||||
|
||||
.add-btn {
|
||||
width: 356rpx;
|
||||
height: 80rpx;
|
||||
border-radius: 40rpx 0 0 40rpx;
|
||||
background-color: var(--ui-BG-Main-light);
|
||||
color: var(--ui-BG-Main);
|
||||
}
|
||||
.add-btn {
|
||||
width: 356rpx;
|
||||
height: 80rpx;
|
||||
border-radius: 40rpx 0 0 40rpx;
|
||||
background-color: var(--ui-BG-Main-light);
|
||||
color: var(--ui-BG-Main);
|
||||
}
|
||||
|
||||
.buy-btn {
|
||||
width: 356rpx;
|
||||
height: 80rpx;
|
||||
border-radius: 0 40rpx 40rpx 0;
|
||||
background: linear-gradient(90deg, var(--ui-BG-Main), var(--ui-BG-Main-gradient));
|
||||
color: #fff;
|
||||
}
|
||||
.buy-btn {
|
||||
width: 356rpx;
|
||||
height: 80rpx;
|
||||
border-radius: 0 40rpx 40rpx 0;
|
||||
background: linear-gradient(90deg, var(--ui-BG-Main), var(--ui-BG-Main-gradient));
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.score-btn {
|
||||
width: 100%;
|
||||
margin: 0 20rpx;
|
||||
height: 80rpx;
|
||||
border-radius: 40rpx;
|
||||
background: linear-gradient(90deg, var(--ui-BG-Main), var(--ui-BG-Main-gradient));
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
.score-btn {
|
||||
width: 100%;
|
||||
margin: 0 20rpx;
|
||||
height: 80rpx;
|
||||
border-radius: 40rpx;
|
||||
background: linear-gradient(90deg, var(--ui-BG-Main), var(--ui-BG-Main-gradient));
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
.ss-modal-box {
|
||||
border-radius: 30rpx 30rpx 0 0;
|
||||
max-height: 1000rpx;
|
||||
.ss-modal-box {
|
||||
border-radius: 30rpx 30rpx 0 0;
|
||||
max-height: 1000rpx;
|
||||
|
||||
.modal-header {
|
||||
position: relative;
|
||||
padding: 80rpx 20rpx 40rpx;
|
||||
.modal-header {
|
||||
position: relative;
|
||||
padding: 80rpx 20rpx 40rpx;
|
||||
|
||||
.sku-image {
|
||||
width: 160rpx;
|
||||
height: 160rpx;
|
||||
border-radius: 10rpx;
|
||||
}
|
||||
.sku-image {
|
||||
width: 160rpx;
|
||||
height: 160rpx;
|
||||
border-radius: 10rpx;
|
||||
}
|
||||
|
||||
.header-right {
|
||||
height: 160rpx;
|
||||
}
|
||||
.header-right {
|
||||
height: 160rpx;
|
||||
}
|
||||
|
||||
.close-icon {
|
||||
position: absolute;
|
||||
top: 10rpx;
|
||||
right: 20rpx;
|
||||
font-size: 46rpx;
|
||||
opacity: 0.2;
|
||||
}
|
||||
.close-icon {
|
||||
position: absolute;
|
||||
top: 10rpx;
|
||||
right: 20rpx;
|
||||
font-size: 46rpx;
|
||||
opacity: 0.2;
|
||||
}
|
||||
|
||||
.goods-title {
|
||||
font-size: 28rpx;
|
||||
font-weight: 500;
|
||||
line-height: 42rpx;
|
||||
}
|
||||
.goods-title {
|
||||
font-size: 28rpx;
|
||||
font-weight: 500;
|
||||
line-height: 42rpx;
|
||||
}
|
||||
|
||||
.score-img {
|
||||
width: 36rpx;
|
||||
height: 36rpx;
|
||||
margin: 0 4rpx;
|
||||
}
|
||||
.score-img {
|
||||
width: 36rpx;
|
||||
height: 36rpx;
|
||||
margin: 0 4rpx;
|
||||
}
|
||||
|
||||
.score-text {
|
||||
font-size: 30rpx;
|
||||
font-weight: 500;
|
||||
color: $red;
|
||||
font-family: OPPOSANS;
|
||||
}
|
||||
.score-text {
|
||||
font-size: 30rpx;
|
||||
font-weight: 500;
|
||||
color: $red;
|
||||
font-family: OPPOSANS;
|
||||
}
|
||||
|
||||
.price-text {
|
||||
font-size: 30rpx;
|
||||
font-weight: 500;
|
||||
color: $red;
|
||||
font-family: OPPOSANS;
|
||||
.price-text {
|
||||
font-size: 30rpx;
|
||||
font-weight: 500;
|
||||
color: $red;
|
||||
font-family: OPPOSANS;
|
||||
|
||||
&::before {
|
||||
content: '¥';
|
||||
font-size: 30rpx;
|
||||
font-weight: 500;
|
||||
color: $red;
|
||||
}
|
||||
}
|
||||
&::before {
|
||||
content: '¥';
|
||||
font-size: 30rpx;
|
||||
font-weight: 500;
|
||||
color: $red;
|
||||
}
|
||||
}
|
||||
|
||||
.stock-text {
|
||||
font-size: 26rpx;
|
||||
color: #999999;
|
||||
}
|
||||
}
|
||||
.stock-text {
|
||||
font-size: 26rpx;
|
||||
color: #999999;
|
||||
}
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
padding: 0 20rpx;
|
||||
.modal-content {
|
||||
padding: 0 20rpx;
|
||||
|
||||
.modal-content-scroll {
|
||||
max-height: 600rpx;
|
||||
.modal-content-scroll {
|
||||
max-height: 600rpx;
|
||||
|
||||
.label-text {
|
||||
font-size: 26rpx;
|
||||
font-weight: 500;
|
||||
}
|
||||
.label-text {
|
||||
font-size: 26rpx;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.buy-num-box {
|
||||
height: 100rpx;
|
||||
}
|
||||
.buy-num-box {
|
||||
height: 100rpx;
|
||||
}
|
||||
|
||||
.spec-btn {
|
||||
height: 60rpx;
|
||||
min-width: 100rpx;
|
||||
padding: 0 30rpx;
|
||||
background: #f4f4f4;
|
||||
border-radius: 30rpx;
|
||||
color: #434343;
|
||||
font-size: 26rpx;
|
||||
margin-right: 10rpx;
|
||||
margin-bottom: 10rpx;
|
||||
}
|
||||
.spec-btn {
|
||||
height: 60rpx;
|
||||
min-width: 100rpx;
|
||||
padding: 0 30rpx;
|
||||
background: #f4f4f4;
|
||||
border-radius: 30rpx;
|
||||
color: #434343;
|
||||
font-size: 26rpx;
|
||||
margin-right: 10rpx;
|
||||
margin-bottom: 10rpx;
|
||||
}
|
||||
|
||||
.disabled-btn {
|
||||
font-weight: 400;
|
||||
color: #c6c6c6;
|
||||
background: #f8f8f8;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
.disabled-btn {
|
||||
font-weight: 400;
|
||||
color: #c6c6c6;
|
||||
background: #f8f8f8;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.iconBox {
|
||||
width: fit-content;
|
||||
height: fit-content;
|
||||
padding: 2rpx 10rpx;
|
||||
background-color: rgb(255, 242, 241);
|
||||
color: #ff2621;
|
||||
font-size: 24rpx;
|
||||
margin-left: 5rpx;
|
||||
}
|
||||
|
||||
.origin-price-text {
|
||||
font-size: 26rpx;
|
||||
font-weight: 400;
|
||||
text-decoration: line-through;
|
||||
color: $gray-c;
|
||||
font-family: OPPOSANS;
|
||||
|
||||
&::before {
|
||||
content: '¥';
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user