【功能完善】商品详情,增加满减送提示

This commit is contained in:
YunaiV
2024-09-16 18:15:13 +08:00
parent b741a1d148
commit 9df0194aeb
8 changed files with 612 additions and 366 deletions
+53 -57
View File
@@ -7,7 +7,7 @@
<view class="type-text ss-flex ss-row-center">满减</view>
<view class="ss-flex-1">
<view class="tip-content" v-for="item in state.activityInfo.rules" :key="item">
{{ formatRewardActivityRule(state.activityInfo, item) }}
{{ item.description }}
</view>
</view>
<image class="activity-left-image" src="/static/activity-left.png" />
@@ -19,9 +19,13 @@
<view class="ss-flex ss-flex-wrap ss-p-x-20 ss-m-t-20 ss-col-top">
<view class="goods-list-box">
<view class="left-list" v-for="item in state.leftGoodsList" :key="item.id">
<s-goods-column class="goods-md-box" size="md" :data="item"
@click="sheep.$router.go('/pages/goods/index', { id: item.id })"
@getHeight="mountMasonry($event, 'left')">
<s-goods-column
class="goods-md-box"
size="md"
:data="item"
@click="sheep.$router.go('/pages/goods/index', { id: item.id })"
@getHeight="mountMasonry($event, 'left')"
>
<template v-slot:cart>
<button class="ss-reset-button cart-btn"> </button>
</template>
@@ -30,9 +34,13 @@
</view>
<view class="goods-list-box">
<view class="right-list" v-for="item in state.rightGoodsList" :key="item.id">
<s-goods-column class="goods-md-box" size="md" :data="item"
@click="sheep.$router.go('/pages/goods/index', { id: item.id })"
@getHeight="mountMasonry($event, 'right')">
<s-goods-column
class="goods-md-box"
size="md"
:data="item"
@click="sheep.$router.go('/pages/goods/index', { id: item.id })"
@getHeight="mountMasonry($event, 'right')"
>
<template v-slot:cart>
<button class="ss-reset-button cart-btn" />
</template>
@@ -41,27 +49,22 @@
</view>
</view>
<uni-load-more v-if="state.pagination.total > 0" :status="state.loadStatus" :content-text="{
<uni-load-more
v-if="state.pagination.total > 0"
:status="state.loadStatus"
:content-text="{
contentdown: '上拉加载更多',
}" @tap="loadMore" />
}"
@tap="loadMore"
/>
</s-layout>
</template>
<script setup>
import {
reactive,
toRaw,
ref
} from 'vue';
import {
onLoad,
onReachBottom
} from '@dcloudio/uni-app';
import { reactive, toRaw, ref } from 'vue';
import { onLoad, onReachBottom } from '@dcloudio/uni-app';
import sheep from '@/sheep';
import _ from 'lodash-es';
import RewardActivityApi from '@/sheep/api/promotion/rewardActivity';
import {
formatRewardActivityRule
} from '@/sheep/hooks/useGoods';
import SpuApi from '@/sheep/api/product/spu';
const state = reactive({
@@ -104,35 +107,31 @@
async function getList() {
// state.loadStatus = 'loading';
// 处理拓展参数
const params = {}
const params = {};
if (state.activityInfo.productScope === 2) {
// const params = toRaw(state.activityInfo.productScopeValues)
// 请求数据
const {
code,
data
} = await SpuApi.getSpuListByIds(state.activityInfo.productScopeValues.join(','));
const { code, data } = await SpuApi.getSpuListByIds(
state.activityInfo.productScopeValues.join(','),
);
if (code !== 0) {
return;
}
// 使用 map 提取每个对象的 id 属性
const ids = data.map(item => item.id);
const ids = data.map((item) => item.id);
// 使用 join 方法将 id 数组连接成一个用逗号分隔的字符串
const idsString = ids.join(',');
// 获取结算信息
settleData.value = await getSettlementByIds(idsString)
settleData.value = await getSettlementByIds(idsString);
// 处理获得的数据
const ms = enrichDataWithSkus(data, settleData.value)
const ms = enrichDataWithSkus(data, settleData.value);
state.pagination.list = ms;
// state.pagination.total = data.total;
// state.loadStatus = state.pagination.list.length < state.pagination.total ? 'more' : 'noMore';
} else if (state.activityInfo.productScope === 3) {
params.categoryIds = state.activityInfo.productScopeValues.join(',');
state.loadStatus = 'loading';
const {
code,
data
} = await SpuApi.getSpuPage({
const { code, data } = await SpuApi.getSpuPage({
pageNo: state.pagination.pageNo,
pageSize: state.pagination.pageSize,
...params,
@@ -141,22 +140,19 @@
return;
}
// 使用 map 提取每个对象的 id 属性
const ids = data.list.map(item => item.id);
const ids = data.list.map((item) => item.id);
// 使用 join 方法将 id 数组连接成一个用逗号分隔的字符串
const idsString = ids.join(',');
// 获取结算信息
settleData.value = await getSettlementByIds(idsString)
settleData.value = await getSettlementByIds(idsString);
// 处理获得的数据
const ms = enrichDataWithSkus(data.list, settleData.value)
const ms = enrichDataWithSkus(data.list, settleData.value);
state.pagination.list = _.concat(state.pagination.list, ms);
state.pagination.total = data.total;
state.loadStatus = state.pagination.list.length < state.pagination.total ? 'more' : 'noMore';
} else {
state.loadStatus = 'loading';
const {
code,
data
} = await SpuApi.getSpuPage({
const { code, data } = await SpuApi.getSpuPage({
pageNo: state.pagination.pageNo,
pageSize: state.pagination.pageSize,
});
@@ -164,13 +160,13 @@
return;
}
// 使用 map 提取每个对象的 id 属性
const ids = data.list.map(item => item.id);
const ids = data.list.map((item) => item.id);
// 使用 join 方法将 id 数组连接成一个用逗号分隔的字符串
const idsString = ids.join(',');
// 获取结算信息
settleData.value = await getSettlementByIds(idsString)
settleData.value = await getSettlementByIds(idsString);
// 处理获得的数据
const ms = enrichDataWithSkus(data.list, settleData.value)
const ms = enrichDataWithSkus(data.list, settleData.value);
state.pagination.list = _.concat(state.pagination.list, ms);
state.pagination.total = data.total;
state.loadStatus = state.pagination.list.length < state.pagination.total ? 'more' : 'noMore';
@@ -178,22 +174,25 @@
mountMasonry();
}
//获取结算信息
const settleData = ref()
const settleData = ref();
async function getSettlementByIds(ids) {
const {
data
} = await SpuApi.getSettlementProduct(ids);
const { data } = await SpuApi.getSettlementProduct(ids);
return data;
}
//计算展示价格的函数
function enrichDataWithSkus(data, array) {
// 创建一个映射,以 id 为键,存储 data 数组中的对象
const dataMap = new Map(data.map(item => [item.id, {
...item
}]));
const dataMap = new Map(
data.map((item) => [
item.id,
{
...item,
},
]),
);
// 遍历 array 数组
array.forEach(item => {
array.forEach((item) => {
// 初始化 discountPrice 和 vipPrice 为 null
let discountPrice = null;
let vipPrice = null;
@@ -201,7 +200,7 @@
let foundType6 = false;
// 遍历 skus 数组,寻找 type 为 4 和 6 的首个条目
item.skus.forEach(sku => {
item.skus.forEach((sku) => {
if (!foundType4 && sku.type === 4) {
discountPrice = sku.price;
foundType4 = true;
@@ -230,10 +229,7 @@
}
// 加载活动信息
async function getActivity(id) {
const {
code,
data
} = await RewardActivityApi.getRewardActivity(id);
const { code, data } = await RewardActivityApi.getRewardActivity(id);
if (code === 0) {
state.activityInfo = data;
}
@@ -312,4 +308,4 @@
line-height: 42rpx;
}
}
</style>
</style>
+218 -29
View File
@@ -27,10 +27,55 @@
dotCur="bg-mask-40"
:seizeHeight="750"
/>
<!-- 限时折扣/会员价的优惠信息 -->
<view class="discount" v-if="state.settlementSku && state.settlementSku.id">
<image class="disImg" :src="sheep.$url.static('/static/img/shop/goods/dis.png')" />
<view class="discountCont">
<view class="disContT">
<view class="disContT1">
<view class="disContT1P">
{{ fen2yuan(state.settlementSku.promotionPrice) }}
</view>
<view class="disContT1End">
直降
{{ fen2yuan(state.settlementSku.price - state.settlementSku.promotionPrice) }}
</view>
</view>
<view class="disContT2" v-if="state.settlementSku.promotionType === 4">
限时折扣
</view>
<view class="disContT2" v-else-if="state.settlementSku.promotionType === 6">
会员折扣
</view>
</view>
<view class="disContB">
<view class="disContB1">
价格{{ fen2yuan(state.settlementSku.price) }} 剩余
{{ state.settlementSku.stock }}
</view>
<view class="disContB2" v-if="state.settlementSku.promotionEndTime > 0">
距结束仅剩
<countDown
:tipText="' '"
:bgColor="bgColor"
:dayText="':'"
:hourText="':'"
:minuteText="':'"
:secondText="' '"
:datatime="state.settlementSku.promotionEndTime / 1000"
:isDay="false"
/>
</view>
</view>
</view>
</view>
<!-- 价格+标题 -->
<view class="title-card detail-card ss-p-y-40 ss-p-x-20">
<view class="ss-flex ss-row-between ss-col-center ss-m-b-26">
<view class="title-card detail-card ss-p-y-30 ss-p-x-20">
<!-- 没有限时折扣/会员价的优惠信息时展示的价格信息 -->
<view
class="ss-flex ss-row-between ss-col-center ss-m-b-26"
v-if="!(state.settlementSku && state.settlementSku.id)"
>
<view class="price-box ss-flex ss-col-bottom">
<view class="price-text ss-m-r-16">
{{ fen2yuan(state.selectedSku.price || state.goodsInfo.price) }}
@@ -44,24 +89,37 @@
</view>
</view>
<view class="discounts-box ss-flex ss-row-between ss-m-b-28">
<!-- 满减送/限时折扣活动的提示 -->
<!-- 查看满减送的描述 -->
<div class="tag-content">
<view class="tag-box ss-flex">
<view
class="tag ss-m-r-10"
v-for="promos in state.activityInfo"
:key="promos.id"
@tap="onActivity"
v-for="coupon in state.couponInfo.slice(0, 1)"
:key="coupon.id"
@tap="onOpenActivity"
>
{{ promos.name }}
[] {{ fen2yuan(coupon.usePrice) }}
{{
coupon.discountType === 1
? '减 ' + fen2yuan(coupon.discountPrice) + ' 元'
: '打 ' + coupon.discountPercent / 10.0 + ' 折'
}}
</view>
<view
v-if="state.rewardActivity && state.rewardActivity.id > 0"
class="tag ss-m-r-10"
v-for="promos in state.rewardActivity.ruleDescriptions.slice(0, 1)"
:key="promos.id"
@tap="onOpenActivity"
>
{{ promos }}
</view>
</view>
</div>
<!-- 优惠劵 -->
<!-- 领取优惠劵的按钮 -->
<view
class="get-coupon-box ss-flex ss-col-center ss-m-l-20"
@tap="state.showModel = true"
@tap="onOpenActivity"
v-if="state.couponInfo.length"
>
<view class="discounts-title ss-m-r-8">领券</view>
@@ -127,19 +185,12 @@
</view>
</detail-tabbar>
<!-- 优惠劵弹窗 -->
<s-coupon-get
v-model="state.couponInfo"
:show="state.showModel"
@close="state.showModel = false"
@get="onGet"
/>
<!-- 满减送/限时折扣活动弹窗 -->
<s-activity-pop
v-model="state.activityInfo"
v-model="state"
:show="state.showActivityModel"
@close="state.showActivityModel = false"
@get="onTakeCoupon"
/>
</block>
</s-layout>
@@ -147,7 +198,7 @@
</template>
<script setup>
import { reactive, computed } from 'vue';
import { reactive, computed, ref } from 'vue';
import { onLoad, onPageScroll } from '@dcloudio/uni-app';
import sheep from '@/sheep';
import CouponApi from '@/sheep/api/promotion/coupon';
@@ -165,7 +216,15 @@
import SpuApi from '@/sheep/api/product/spu';
onPageScroll(() => {});
import countDown from '@/sheep/components/countDown/index.vue';
const bgColor = {
bgColor: '#E93323',
Color: '#fff',
width: '44rpx',
timeTxtwidth: '16rpx',
isDay: true,
};
const isLogin = computed(() => sheep.$store('user').isLogin);
const state = reactive({
goodsId: 0,
@@ -173,16 +232,18 @@
goodsInfo: {}, // SPU 信息
showSelectSku: false, // 是否展示 SKU 选择弹窗
selectedSku: {}, // 选中的 SKU
settlementSku: {}, // 结算的 SKU:由于 selectedSku 不进行默认选中,所以初始使用结算价格最低的 SKU 作为基础展示
showModel: false, // 是否展示 Coupon 优惠劵的弹窗
couponInfo: [], // 可领取的 Coupon 优惠劵的列表
showActivityModel: false, // 【满减送/限时折扣】是否展示 Activity 营销活动的弹窗
activityInfo: [], // 【满减送/限时折扣】可参与的 Activity 营销活动的列表 TODO 芋艿:正在接入中
rewardActivity: {}, // 【满减送】活动
activityList: [], // 【秒杀/拼团/砍价】可参与的 Activity 营销活动的列表
});
// 规格变更
function onSkuChange(e) {
state.selectedSku = e;
state.settlementSku = e;
}
// 添加购物车
@@ -196,7 +257,7 @@
// 立即购买
function onBuy(e) {
if (!state.selectedSku.id) {
if (!e.id) {
sheep.$helper.toast('请选择商品规格');
return;
}
@@ -213,13 +274,13 @@
});
}
// 营销活动
function onActivity() {
// 打开营销弹窗
function onOpenActivity() {
state.showActivityModel = true;
}
// 立即领取
async function onGet(id) {
// 立即领取优惠劵
async function onTakeCoupon(id) {
const { code } = await CouponApi.takeCoupon(id);
if (code !== 0) {
return;
@@ -261,6 +322,36 @@
}
}
async function getSettlementByIds(ids) {
let { data, code } = await SpuApi.getSettlementProduct(ids);
if (code !== 0 || data.length !== 1) {
return;
}
data = data[0];
// 补充 SKU 的价格信息
state.goodsInfo.skus.forEach((sku) => {
data.skus.forEach((item) => {
if (sku.id === item.id) {
sku.promotionType = item.promotionType;
sku.promotionPrice = item.promotionPrice;
sku.promotionId = item.promotionId;
sku.promotionEndTime = item.promotionEndTime;
}
});
});
// 选择有 promotionPrice 且最小的
state.settlementSku = state.goodsInfo.skus
.filter((sku) => sku.stock > 0 && sku.promotionPrice > 0)
.reduce((prev, curr) => (prev.promotionPrice < curr.promotionPrice ? prev : curr));
// 设置满减送活动
if (data.rewardActivity) {
state.rewardActivity = data.rewardActivity;
}
}
onLoad((options) => {
// 非法参数
if (!options.id) {
@@ -278,7 +369,6 @@
// 加载到商品
state.skeletonLoading = false;
state.goodsInfo = res.data;
// 加载是否收藏
if (isLogin.value) {
FavoriteApi.isFavoriteExists(state.goodsId, 'goods').then((res) => {
@@ -293,13 +383,15 @@
// 2. 加载优惠劵信息
getCoupon();
// 3. 获得单个商品,进行中的拼团、秒杀、砍价活动信息
// 3. 加载营销活动信息
ActivityApi.getActivityListBySpuId(state.goodsId).then((res) => {
if (res.code !== 0) {
return;
}
state.activityList = res.data;
});
//获取结算信息
getSettlementByIds(state.goodsId);
});
</script>
@@ -448,4 +540,101 @@
color: #333333;
}
}
// 限时折扣
.discount {
width: 750rpx;
height: 100rpx;
// background-color: red;
overflow: hidden;
position: relative;
}
.disImg {
width: 750rpx;
height: 100rpx;
position: absolute;
top: 0;
z-index: -1;
}
.discountCont {
width: 680rpx;
height: 90rpx;
margin: 10rpx auto 0 auto;
// background-color: gold;
}
.disContT {
width: 680rpx;
height: 50rpx;
display: flex;
justify-content: space-between;
}
.disContT1 {
width: 400rpx;
height: 50rpx;
// background-color: green;
display: flex;
justify-content: flex-start;
align-items: center;
}
.disContT2 {
width: 200rpx;
height: 50rpx;
line-height: 50rpx;
// background-color: gold;
font-size: 30rpx;
text-align: end;
color: white;
font-weight: bolder;
font-style: oblique 20deg;
letter-spacing: 0.1rem;
}
.disContT1P {
color: white;
font-weight: bold;
font-size: 28rpx;
}
.disContT1End {
// width: 180rpx;
padding: 0 10rpx;
height: 30rpx;
line-height: 28rpx;
text-align: center;
font-weight: bold;
background-color: white;
color: #ff3000;
font-size: 23rpx;
border-radius: 20rpx;
margin-left: 10rpx;
}
.disContB {
width: 680rpx;
height: 40rpx;
display: flex;
justify-content: space-between;
font-size: 20rpx;
color: white;
align-items: center;
}
.disContB1 {
width: 300rpx;
height: 40rpx;
line-height: 40rpx;
}
.disContB2 {
width: 300rpx;
height: 40rpx;
line-height: 40rpx;
display: flex;
justify-content: flex-end;
}
</style>