【代码优化】商城:优化 /promotion/activity/list-by-spu-id 的逻辑

pull/98/MERGE
YunaiV 2024-09-15 17:59:42 +08:00
parent 49e8b9f5c3
commit eb3d0ff6b0
3 changed files with 362 additions and 317 deletions

View File

@ -1,175 +1,225 @@
<template> <template>
<view> <view>
<s-layout :onShareAppMessage="shareInfo" navbar="goods"> <s-layout :onShareAppMessage="shareInfo" navbar="goods">
<!-- 标题栏 --> <!-- 标题栏 -->
<detailNavbar /> <detailNavbar />
<!-- 骨架屏 --> <!-- 骨架屏 -->
<detailSkeleton v-if="state.skeletonLoading" /> <detailSkeleton v-if="state.skeletonLoading" />
<!-- 下架/售罄提醒 --> <!-- 下架/售罄提醒 -->
<s-empty v-else-if="state.goodsInfo === null" text="商品不存在或已下架" icon="/static/soldout-empty.png" showAction <s-empty
actionText="再逛逛" actionUrl="/pages/goods/list" /> v-else-if="state.goodsInfo === null"
<block v-else> text="商品不存在或已下架"
<view class="detail-swiper-selector"> icon="/static/soldout-empty.png"
<!-- 商品轮播图 --> showAction
<su-swiper class="ss-m-b-14" isPreview :list="formatGoodsSwiper(state.goodsInfo.sliderPicUrls)" actionText="再逛逛"
otStyle="tag" imageMode="widthFix" dotCur="bg-mask-40" :seizeHeight="750" /> actionUrl="/pages/goods/list"
/>
<block v-else>
<view class="detail-swiper-selector">
<!-- 商品轮播图 -->
<su-swiper
class="ss-m-b-14"
isPreview
:list="formatGoodsSwiper(state.goodsInfo.sliderPicUrls)"
otStyle="tag"
imageMode="widthFix"
dotCur="bg-mask-40"
:seizeHeight="750"
/>
<!-- 价格+标题 --> <!-- 价格+标题 -->
<view class="title-card detail-card ss-p-y-40 ss-p-x-20"> <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="ss-flex ss-row-between ss-col-center ss-m-b-26">
<view class="price-box ss-flex ss-col-bottom"> <view class="price-box ss-flex ss-col-bottom">
<view class="price-text ss-m-r-16"> <view class="price-text ss-m-r-16">
{{ fen2yuan(state.selectedSku.price || state.goodsInfo.price) }} {{ fen2yuan(state.selectedSku.price || state.goodsInfo.price) }}
</view> </view>
<view class="origin-price-text" v-if="state.goodsInfo.marketPrice > 0"> <view class="origin-price-text" v-if="state.goodsInfo.marketPrice > 0">
{{ fen2yuan(state.selectedSku.marketPrice || state.goodsInfo.marketPrice) }} {{ fen2yuan(state.selectedSku.marketPrice || state.goodsInfo.marketPrice) }}
</view> </view>
</view> </view>
<view class="sales-text"> <view class="sales-text">
{{ formatSales('exact', state.goodsInfo.salesCount) }} {{ formatSales('exact', state.goodsInfo.salesCount) }}
</view> </view>
</view> </view>
<view class="discounts-box ss-flex ss-row-between ss-m-b-28"> <view class="discounts-box ss-flex ss-row-between ss-m-b-28">
<!-- 满减送/限时折扣活动的提示 --> <!-- 满减送/限时折扣活动的提示 -->
<div class="tag-content"> <div class="tag-content">
<view class="tag-box ss-flex"> <view class="tag-box ss-flex">
<view class="tag ss-m-r-10" v-for="promos in state.activityInfo" <view
:key="promos.id" @tap="onActivity"> class="tag ss-m-r-10"
{{ promos.name }} v-for="promos in state.activityInfo"
</view> :key="promos.id"
</view> @tap="onActivity"
</div> >
{{ promos.name }}
</view>
</view>
</div>
<!-- 优惠劵 --> <!-- 优惠劵 -->
<view class="get-coupon-box ss-flex ss-col-center ss-m-l-20" @tap="state.showModel = true" <view
v-if="state.couponInfo.length"> class="get-coupon-box ss-flex ss-col-center ss-m-l-20"
<view class="discounts-title ss-m-r-8">领券</view> @tap="state.showModel = true"
<text class="cicon-forward"></text> v-if="state.couponInfo.length"
</view> >
</view> <view class="discounts-title ss-m-r-8">领券</view>
<view class="title-text ss-line-2 ss-m-b-6">{{ state.goodsInfo.name }}</view> <text class="cicon-forward"></text>
<view class="subtitle-text ss-line-1">{{ state.goodsInfo.introduction }}</view> </view>
</view> </view>
<view class="title-text ss-line-2 ss-m-b-6">{{ state.goodsInfo.name }}</view>
<view class="subtitle-text ss-line-1">{{ state.goodsInfo.introduction }}</view>
</view>
<!-- 功能卡片 --> <!-- 功能卡片 -->
<view class="detail-cell-card detail-card ss-flex-col"> <view class="detail-cell-card detail-card ss-flex-col">
<detail-cell-sku v-model="state.selectedSku.goods_sku_text" :sku="state.selectedSku" <detail-cell-sku
@tap="state.showSelectSku = true" /> v-model="state.selectedSku.goods_sku_text"
</view> :sku="state.selectedSku"
@tap="state.showSelectSku = true"
/>
</view>
<!-- 规格与数量弹框 --> <!-- 规格与数量弹框 -->
<s-select-sku :goodsInfo="state.goodsInfo" :show="state.showSelectSku" @addCart="onAddCart" <s-select-sku
@buy="onBuy" @change="onSkuChange" @close="state.showSelectSku = false" /> :goodsInfo="state.goodsInfo"
</view> :show="state.showSelectSku"
@addCart="onAddCart"
@buy="onBuy"
@change="onSkuChange"
@close="state.showSelectSku = false"
/>
</view>
<!-- 评价 --> <!-- 评价 -->
<detail-comment-card class="detail-comment-selector" :goodsId="state.goodsId" /> <detail-comment-card class="detail-comment-selector" :goodsId="state.goodsId" />
<!-- 详情 --> <!-- 详情 -->
<detail-content-card class="detail-content-selector" :content="state.goodsInfo.description" /> <detail-content-card
class="detail-content-selector"
:content="state.goodsInfo.description"
/>
<!-- 活动跳转拼团/秒杀/砍价活动 --> <!-- 活动跳转拼团/秒杀/砍价活动 -->
<detail-activity-tip v-if="state.activityList.length > 0" :activity-list="state.activityList" /> <detail-activity-tip
v-if="state.activityList.length > 0"
:activity-list="state.activityList"
/>
<!-- 详情 tabbar --> <!-- 详情 tabbar -->
<detail-tabbar v-model="state.goodsInfo"> <detail-tabbar v-model="state.goodsInfo">
<view class="buy-box ss-flex ss-col-center ss-p-r-20" v-if="state.goodsInfo.stock > 0"> <view class="buy-box ss-flex ss-col-center ss-p-r-20" v-if="state.goodsInfo.stock > 0">
<button class="ss-reset-button add-btn ui-Shadow-Main" @tap="state.showSelectSku = true"> <button
加入购物车 class="ss-reset-button add-btn ui-Shadow-Main"
</button> @tap="state.showSelectSku = true"
<button class="ss-reset-button buy-btn ui-Shadow-Main" @tap="state.showSelectSku = true"> >
立即购买 加入购物车
</button> </button>
</view> <button
<view class="buy-box ss-flex ss-col-center ss-p-r-20" v-else> class="ss-reset-button buy-btn ui-Shadow-Main"
<button class="ss-reset-button disabled-btn" disabled> 已售罄 </button> @tap="state.showSelectSku = true"
</view> >
</detail-tabbar> 立即购买
</button>
</view>
<view class="buy-box ss-flex ss-col-center ss-p-r-20" v-else>
<button class="ss-reset-button disabled-btn" disabled> 已售罄 </button>
</view>
</detail-tabbar>
<!-- 优惠劵弹窗 --> <!-- 优惠劵弹窗 -->
<s-coupon-get v-model="state.couponInfo" :show="state.showModel" @close="state.showModel = false" <s-coupon-get
@get="onGet" /> v-model="state.couponInfo"
:show="state.showModel"
@close="state.showModel = false"
@get="onGet"
/>
<!-- 满减送/限时折扣活动弹窗 --> <!-- 满减送/限时折扣活动弹窗 -->
<s-activity-pop v-model="state.activityInfo" :show="state.showActivityModel" <s-activity-pop
@close="state.showActivityModel = false" /> v-model="state.activityInfo"
</block> :show="state.showActivityModel"
</s-layout> @close="state.showActivityModel = false"
</view> />
</block>
</s-layout>
</view>
</template> </template>
<script setup> <script setup>
import { reactive, computed } from 'vue'; import { reactive, computed } from 'vue';
import { onLoad, onPageScroll } from '@dcloudio/uni-app'; import { onLoad, onPageScroll } from '@dcloudio/uni-app';
import sheep from '@/sheep'; import sheep from '@/sheep';
import CouponApi from '@/sheep/api/promotion/coupon'; import CouponApi from '@/sheep/api/promotion/coupon';
import ActivityApi from '@/sheep/api/promotion/activity'; import ActivityApi from '@/sheep/api/promotion/activity';
import FavoriteApi from '@/sheep/api/product/favorite'; import FavoriteApi from '@/sheep/api/product/favorite';
import { formatSales, formatGoodsSwiper, fen2yuan } from '@/sheep/hooks/useGoods'; import { formatSales, formatGoodsSwiper, fen2yuan } from '@/sheep/hooks/useGoods';
import detailNavbar from './components/detail/detail-navbar.vue'; import detailNavbar from './components/detail/detail-navbar.vue';
import detailCellSku from './components/detail/detail-cell-sku.vue'; import detailCellSku from './components/detail/detail-cell-sku.vue';
import detailTabbar from './components/detail/detail-tabbar.vue'; import detailTabbar from './components/detail/detail-tabbar.vue';
import detailSkeleton from './components/detail/detail-skeleton.vue'; import detailSkeleton from './components/detail/detail-skeleton.vue';
import detailCommentCard from './components/detail/detail-comment-card.vue'; import detailCommentCard from './components/detail/detail-comment-card.vue';
import detailContentCard from './components/detail/detail-content-card.vue'; import detailContentCard from './components/detail/detail-content-card.vue';
import detailActivityTip from './components/detail/detail-activity-tip.vue'; import detailActivityTip from './components/detail/detail-activity-tip.vue';
import { isEmpty } from 'lodash-es'; import { isEmpty } from 'lodash-es';
import SpuApi from '@/sheep/api/product/spu'; import SpuApi from '@/sheep/api/product/spu';
onPageScroll(() => {}); onPageScroll(() => {});
const isLogin = computed(() => sheep.$store('user').isLogin); const isLogin = computed(() => sheep.$store('user').isLogin);
const state = reactive({ const state = reactive({
goodsId: 0, goodsId: 0,
skeletonLoading: true, // SPU skeletonLoading: true, // SPU
goodsInfo: {}, // SPU goodsInfo: {}, // SPU
showSelectSku: false, // SKU showSelectSku: false, // SKU
selectedSku: {}, // SKU selectedSku: {}, // SKU
showModel: false, // Coupon showModel: false, // Coupon
couponInfo: [], // Coupon couponInfo: [], // Coupon
showActivityModel: false, // / Activity showActivityModel: false, // / Activity
activityInfo: [], // / Activity activityInfo: [], // / Activity TODO
activityList: [], // // Activity activityList: [], // // Activity
}); });
// //
function onSkuChange(e) { function onSkuChange(e) {
state.selectedSku = e; state.selectedSku = e;
} }
// //
function onAddCart(e) { function onAddCart(e) {
if (!e.id) { if (!e.id) {
sheep.$helper.toast('请选择商品规格'); sheep.$helper.toast('请选择商品规格');
return; return;
} }
sheep.$store('cart').add(e); sheep.$store('cart').add(e);
} }
// //
function onBuy(e) { function onBuy(e) {
if (!state.selectedSku.id) { if (!state.selectedSku.id) {
sheep.$helper.toast('请选择商品规格'); sheep.$helper.toast('请选择商品规格');
return; return;
} }
sheep.$router.go('/pages/order/confirm', { sheep.$router.go('/pages/order/confirm', {
data: JSON.stringify({ data: JSON.stringify({
items: [{ items: [
skuId: e.id, {
count: e.goods_num, skuId: e.id,
categoryId: state.goodsInfo.categoryId count: e.goods_num,
}] categoryId: state.goodsInfo.categoryId,
},
],
}), }),
}); });
} }
// //
function onActivity() { function onActivity() {
state.showActivityModel = true; state.showActivityModel = true;
} }
// //
async function onGet(id) { async function onGet(id) {
const { code } = await CouponApi.takeCoupon(id); const { code } = await CouponApi.takeCoupon(id);
if (code !== 0) { if (code !== 0) {
return; return;
@ -180,26 +230,29 @@
setTimeout(() => { setTimeout(() => {
getCoupon(); getCoupon();
}, 1000); }, 1000);
} }
const shareInfo = computed(() => { const shareInfo = computed(() => {
if (isEmpty(state.goodsInfo)) return {}; if (isEmpty(state.goodsInfo)) return {};
return sheep.$platform.share.getShareInfo({ return sheep.$platform.share.getShareInfo(
title: state.goodsInfo.name, {
image: sheep.$url.cdn(state.goodsInfo.picUrl), title: state.goodsInfo.name,
desc: state.goodsInfo.introduction, image: sheep.$url.cdn(state.goodsInfo.picUrl),
params: { desc: state.goodsInfo.introduction,
page: '2', params: {
query: state.goodsInfo.id, page: '2',
}, query: state.goodsInfo.id,
}, { },
type: 'goods', // },
title: state.goodsInfo.name, // {
image: sheep.$url.cdn(state.goodsInfo.picUrl), // type: 'goods', //
price: fen2yuan(state.goodsInfo.price), // title: state.goodsInfo.name, //
original_price: fen2yuan(state.goodsInfo.marketPrice), // image: sheep.$url.cdn(state.goodsInfo.picUrl), //
}); price: fen2yuan(state.goodsInfo.price), //
}); original_price: fen2yuan(state.goodsInfo.marketPrice), //
},
);
});
async function getCoupon() { async function getCoupon() {
const { code, data } = await CouponApi.getCouponTemplateList(state.goodsId, 2, 10); const { code, data } = await CouponApi.getCouponTemplateList(state.goodsId, 2, 10);
@ -208,23 +261,23 @@
} }
} }
onLoad((options) => { onLoad((options) => {
// //
if (!options.id) { if (!options.id) {
state.goodsInfo = null; state.goodsInfo = null;
return; return;
} }
state.goodsId = options.id; state.goodsId = options.id;
// 1. // 1.
SpuApi.getSpuDetail(state.goodsId).then((res) => { SpuApi.getSpuDetail(state.goodsId).then((res) => {
// //
if (res.code !== 0 || !res.data) { if (res.code !== 0 || !res.data) {
state.goodsInfo = null; state.goodsInfo = null;
return; return;
} }
// //
state.skeletonLoading = false; state.skeletonLoading = false;
state.goodsInfo = res.data; state.goodsInfo = res.data;
// //
if (isLogin.value) { if (isLogin.value) {
@ -235,172 +288,164 @@
state.goodsInfo.favorite = res.data; state.goodsInfo.favorite = res.data;
}); });
} }
}); });
// 2. // 2.
getCoupon(); getCoupon();
// 3. // 3.
ActivityApi.getActivityListBySpuId(state.goodsId).then((res) => { ActivityApi.getActivityListBySpuId(state.goodsId).then((res) => {
if (res.code !== 0) { if (res.code !== 0) {
return; return;
} }
res.data.forEach(activity => { state.activityList = res.data;
if ([1, 2, 3].includes(activity.type)) { // // });
state.activityList.push(activity); });
} else if (activity.type === 5) { //
state.activityInfo.push(activity);
} else { // TODO puhui999
console.log('待实现!优先级不高');
}
})
});
});
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.detail-card { .detail-card {
background-color: #ffff; background-color: #ffff;
margin: 14rpx 20rpx; margin: 14rpx 20rpx;
border-radius: 10rpx; border-radius: 10rpx;
overflow: hidden; overflow: hidden;
} }
// //
.title-card { .title-card {
.price-box { .price-box {
.price-text { .price-text {
font-size: 42rpx; font-size: 42rpx;
font-weight: 500; font-weight: 500;
color: #ff3000; color: #ff3000;
line-height: 30rpx; line-height: 30rpx;
font-family: OPPOSANS; font-family: OPPOSANS;
&::before { &::before {
content: '¥'; content: '¥';
font-size: 30rpx; font-size: 30rpx;
} }
} }
.origin-price-text { .origin-price-text {
font-size: 26rpx; font-size: 26rpx;
font-weight: 400; font-weight: 400;
text-decoration: line-through; text-decoration: line-through;
color: $gray-c; color: $gray-c;
font-family: OPPOSANS; font-family: OPPOSANS;
&::before { &::before {
content: '¥'; content: '¥';
} }
} }
} }
.sales-text { .sales-text {
font-size: 26rpx; font-size: 26rpx;
font-weight: 500; font-weight: 500;
color: $gray-c; color: $gray-c;
} }
.discounts-box { .discounts-box {
.tag-content { .tag-content {
flex: 1; flex: 1;
min-width: 0; min-width: 0;
white-space: nowrap; white-space: nowrap;
} }
.tag-box { .tag-box {
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
} }
.tag { .tag {
flex-shrink: 0; flex-shrink: 0;
padding: 4rpx 10rpx; padding: 4rpx 10rpx;
font-size: 24rpx; font-size: 24rpx;
font-weight: 500; font-weight: 500;
border-radius: 4rpx; border-radius: 4rpx;
color: var(--ui-BG-Main); color: var(--ui-BG-Main);
background: var(--ui-BG-Main-tag); background: var(--ui-BG-Main-tag);
} }
.discounts-title { .discounts-title {
font-size: 24rpx; font-size: 24rpx;
font-weight: 500; font-weight: 500;
color: var(--ui-BG-Main); color: var(--ui-BG-Main);
line-height: normal; line-height: normal;
} }
.cicon-forward { .cicon-forward {
color: var(--ui-BG-Main); color: var(--ui-BG-Main);
font-size: 24rpx; font-size: 24rpx;
line-height: normal; line-height: normal;
margin-top: 4rpx; margin-top: 4rpx;
} }
} }
.title-text { .title-text {
font-size: 30rpx; font-size: 30rpx;
font-weight: bold; font-weight: bold;
line-height: 42rpx; line-height: 42rpx;
} }
.subtitle-text { .subtitle-text {
font-size: 26rpx; font-size: 26rpx;
font-weight: 400; font-weight: 400;
color: $dark-9; color: $dark-9;
line-height: 42rpx; line-height: 42rpx;
} }
} }
// //
.buy-box { .buy-box {
.add-btn { .add-btn {
width: 214rpx; width: 214rpx;
height: 72rpx; height: 72rpx;
font-weight: 500; font-weight: 500;
font-size: 28rpx; font-size: 28rpx;
border-radius: 40rpx 0 0 40rpx; border-radius: 40rpx 0 0 40rpx;
background-color: var(--ui-BG-Main-light); background-color: var(--ui-BG-Main-light);
color: var(--ui-BG-Main); color: var(--ui-BG-Main);
} }
.buy-btn { .buy-btn {
width: 214rpx; width: 214rpx;
height: 72rpx; height: 72rpx;
font-weight: 500; font-weight: 500;
font-size: 28rpx; font-size: 28rpx;
border-radius: 0 40rpx 40rpx 0; border-radius: 0 40rpx 40rpx 0;
background: linear-gradient(90deg, var(--ui-BG-Main), var(--ui-BG-Main-gradient)); background: linear-gradient(90deg, var(--ui-BG-Main), var(--ui-BG-Main-gradient));
color: $white; color: $white;
} }
.disabled-btn { .disabled-btn {
width: 428rpx; width: 428rpx;
height: 72rpx; height: 72rpx;
border-radius: 40rpx; border-radius: 40rpx;
background: #999999; background: #999999;
color: $white; color: $white;
} }
} }
.model-box { .model-box {
height: 60vh; height: 60vh;
.model-content { .model-content {
height: 56vh; height: 56vh;
} }
.title { .title {
font-size: 36rpx; font-size: 36rpx;
font-weight: bold; font-weight: bold;
color: #333333; color: #333333;
} }
.subtitle { .subtitle {
font-size: 26rpx; font-size: 26rpx;
font-weight: 500; font-weight: 500;
color: #333333; color: #333333;
} }
} }
</style> </style>

View File

@ -1,7 +1,7 @@
import request from '@/sheep/request'; import request from '@/sheep/request';
const ActivityApi = { const ActivityApi = {
// 获得单个商品,近期参与的每个活动 // 获得单个商品,进行中的拼团、秒杀、砍价活动信息
getActivityListBySpuId: (spuId) => { getActivityListBySpuId: (spuId) => {
return request({ return request({
url: '/promotion/activity/list-by-spu-id', url: '/promotion/activity/list-by-spu-id',

View File

@ -23,7 +23,7 @@
:subTitleColor="data.fields.introduction.color" :subTitleColor="data.fields.introduction.color"
:topRadius="data.borderRadiusTop" :topRadius="data.borderRadiusTop"
:bottomRadius="data.borderRadiusBottom" :bottomRadius="data.borderRadiusBottom"
@click="sheep.$router.go('/pages/goods/groupon', { id: item.activityId })" @click="sheep.$router.go('/pages/goods/seckill', { id: item.activityId })"
> >
<!-- 购买按钮 --> <!-- 购买按钮 -->
<template v-slot:cart> <template v-slot:cart>
@ -56,7 +56,7 @@
:subTitleColor="data.fields.introduction.color" :subTitleColor="data.fields.introduction.color"
:topRadius="data.borderRadiusTop" :topRadius="data.borderRadiusTop"
:bottomRadius="data.borderRadiusBottom" :bottomRadius="data.borderRadiusBottom"
@tap="sheep.$router.go('/pages/goods/groupon', { id: item.activityId })" @tap="sheep.$router.go('/pages/goods/seckill', { id: item.activityId })"
> >
<!-- 购买按钮 --> <!-- 购买按钮 -->
<template v-slot:cart> <template v-slot:cart>
@ -91,7 +91,7 @@
:topRadius="data.borderRadiusTop" :topRadius="data.borderRadiusTop"
:bottomRadius="data.borderRadiusBottom" :bottomRadius="data.borderRadiusBottom"
:titleWidth="330 - marginLeft - marginRight" :titleWidth="330 - marginLeft - marginRight"
@click="sheep.$router.go('/pages/goods/groupon', { id: item.activityId })" @click="sheep.$router.go('/pages/goods/seckill', { id: item.activityId })"
@getHeight="calculateGoodsColumn($event, 'left')" @getHeight="calculateGoodsColumn($event, 'left')"
> >
<!-- 购买按钮 --> <!-- 购买按钮 -->
@ -121,7 +121,7 @@
:topRadius="data.borderRadiusTop" :topRadius="data.borderRadiusTop"
:bottomRadius="data.borderRadiusBottom" :bottomRadius="data.borderRadiusBottom"
:titleWidth="330 - marginLeft - marginRight" :titleWidth="330 - marginLeft - marginRight"
@click="sheep.$router.go('/pages/goods/groupon', { id: item.activityId })" @click="sheep.$router.go('/pages/goods/seckill', { id: item.activityId })"
@getHeight="calculateGoodsColumn($event, 'right')" @getHeight="calculateGoodsColumn($event, 'right')"
> >
<!-- 购买按钮 --> <!-- 购买按钮 -->