!101 批量优化或修改BUG

Merge pull request !101 from 痴货/develop-mall
pull/102/MERGE
芋道源码 2024-09-15 13:13:26 +00:00 committed by Gitee
commit ba56d9843f
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
16 changed files with 1995 additions and 940 deletions

View File

@ -19,13 +19,9 @@
<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"
<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')"
>
@getHeight="mountMasonry($event, 'left')">
<template v-slot:cart>
<button class="ss-reset-button cart-btn"> </button>
</template>
@ -34,13 +30,9 @@
</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"
<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')"
>
@getHeight="mountMasonry($event, 'right')">
<template v-slot:cart>
<button class="ss-reset-button cart-btn" />
</template>
@ -49,23 +41,27 @@
</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 } 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 {
formatRewardActivityRule
} from '@/sheep/hooks/useGoods';
import SpuApi from '@/sheep/api/product/spu';
const state = reactive({
@ -106,16 +102,37 @@
//
async function getList() {
// state.loadStatus = 'loading';
//
const params = {};
const params = {}
if (state.activityInfo.productScope === 2) {
params.ids = state.activityInfo.productSpuIds.join(',');
} else if (state.activityInfo.productScope === 3) {
params.categoryIds = state.activityInfo.productSpuIds.join(',');
}
// const params = toRaw(state.activityInfo.productScopeValues)
//
const {
code,
data
} = await SpuApi.getSpuListByIds(state.activityInfo.productScopeValues.join(','));
if (code !== 0) {
return;
}
// 使 map id
const ids = data.map(item => item.id);
// 使 join id
const idsString = ids.join(',');
//
settleData.value = await getSettlementByIds(idsString)
//
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,
@ -123,15 +140,100 @@
if (code !== 0) {
return;
}
state.pagination.list = _.concat(state.pagination.list, data.list);
// 使 map id
const ids = data.list.map(item => item.id);
// 使 join id
const idsString = ids.join(',');
//
settleData.value = await getSettlementByIds(idsString)
//
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({
pageNo: state.pagination.pageNo,
pageSize: state.pagination.pageSize,
});
if (code !== 0) {
return;
}
// 使 map id
const ids = data.list.map(item => item.id);
// 使 join id
const idsString = ids.join(',');
//
settleData.value = await getSettlementByIds(idsString)
//
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';
}
mountMasonry();
}
//
const settleData = ref()
async function getSettlementByIds(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
}]));
// array
array.forEach(item => {
// discountPrice vipPrice null
let discountPrice = null;
let vipPrice = null;
let foundType4 = false;
let foundType6 = false;
// skus type 4 6
item.skus.forEach(sku => {
if (!foundType4 && sku.type === 4) {
discountPrice = sku.price;
foundType4 = true;
}
if (!foundType6 && sku.type === 6) {
vipPrice = sku.price;
foundType6 = true;
}
// type 4 6
if (foundType4 && foundType6) {
return;
}
});
// dataMap
if (dataMap.has(item.id)) {
dataMap.get(item.id).discountPrice = discountPrice;
dataMap.get(item.id).vipPrice = vipPrice;
dataMap.get(item.id).reward = item.reward;
}
});
//
return Array.from(dataMap.values());
}
//
async function getActivity(id) {
const { code, data } = await RewardActivityApi.getRewardActivity(id);
const {
code,
data
} = await RewardActivityApi.getRewardActivity(id);
if (code === 0) {
state.activityInfo = data;
}
@ -154,28 +256,32 @@
onLoad(async (options) => {
state.activityId = options.activityId;
await getActivity(state.activityId);
await getList(state.activityId);
await getList();
});
</script>
<style lang="scss" scoped>
.goods-list-box {
width: 50%;
box-sizing: border-box;
.left-list {
margin-right: 10rpx;
margin-bottom: 20rpx;
}
.right-list {
margin-left: 10rpx;
margin-bottom: 20rpx;
}
}
.tip-box {
background: #fff0e7;
padding: 20rpx;
width: 100%;
position: relative;
box-sizing: border-box;
.activity-left-image {
position: absolute;
bottom: 0;
@ -183,6 +289,7 @@
width: 58rpx;
height: 36rpx;
}
.activity-right-image {
position: absolute;
top: 0;
@ -190,12 +297,14 @@
width: 72rpx;
height: 50rpx;
}
.type-text {
font-size: 26rpx;
font-weight: 500;
color: #ff6000;
line-height: 42rpx;
}
.tip-content {
font-size: 26rpx;
font-weight: 500;

View File

@ -2,10 +2,7 @@
<template>
<s-layout navbar="inner" :bgStyle="{ color: 'rgb(245,28,19)' }">
<!--顶部背景图-->
<view
class="page-bg"
:style="[{ marginTop: '-' + Number(statusBarHeight + 88) + 'rpx' }]"
></view>
<view class="page-bg" :style="[{ marginTop: '-' + Number(statusBarHeight + 88) + 'rpx' }]"></view>
<!-- 时间段轮播图 -->
<view class="header" v-if="activeTimeConfig?.sliderPicUrls?.length > 0">
<swiper indicator-dots="true" autoplay="true" :circular="true" interval="3000" duration="1500"
@ -26,13 +23,12 @@
</view>
<scroll-view class="time-list" :scroll-into-view="activeTimeElId" scroll-x scroll-with-animation>
<view v-for="(config, index) in timeConfigList" :key="index"
:class="['item', { active: activeTimeIndex === index}]"
:id="`timeItem${index}`"
@tap="handleChangeTimeConfig(index)">
:class="['item', { active: activeTimeIndex === index}]" :id="`timeItem${index}`"
@tap="handleChangeTimeConfig(index,config.id)">
<!-- 活动起始时间 -->
<view class="time">{{ config.startTime }}</view>
<!-- 活动状态 -->
<view class="status">{{ config.status }}</view>
<view class="status">{{ config?.status }}</view>
</view>
</scroll-view>
</view>
@ -57,69 +53,89 @@
</view>
<!-- 活动列表 -->
<scroll-view
class="scroll-box"
:style="{ height: pageHeight + 'rpx' }"
scroll-y="true"
:scroll-with-animation="false"
:enable-back-to-top="true"
>
<scroll-view class="scroll-box" :style="{ height: pageHeight + 'rpx' }" scroll-y="true"
:scroll-with-animation="false" :enable-back-to-top="true">
<view class="goods-box ss-m-b-20" v-for="activity in activityList" :key="activity.id">
<s-goods-column
size="lg"
:data="{ ...activity, price: activity.seckillPrice }"
:goodsFields="goodsFields"
:seckillTag="true"
@click="sheep.$router.go('/pages/goods/seckill', { id: activity.id })"
>
<s-goods-column size="lg" :data="{ ...activity, price: activity.seckillPrice }"
:goodsFields="goodsFields" :seckillTag="true">
<!-- 抢购进度 -->
<template #activity>
<view class="limit">限量 <text class="ss-m-l-5">{{ activity.stock}} {{activity.unitName}}</text></view>
<view class="limit">限量 <text class="ss-m-l-5">{{ activity.stock}}
{{activity.unitName}}</text></view>
<su-progress :percentage="activity.percent" strokeWidth="10" textInside isAnimate />
</template>
<!-- 抢购按钮 -->
<template #cart>
<button :class="['ss-reset-button cart-btn', { disabled: activeTimeConfig.status === TimeStatusEnum.END }]">
<span v-if="activeTimeConfig?.status === TimeStatusEnum.WAIT_START"></span>
<span v-else-if="activeTimeConfig?.status === TimeStatusEnum.STARTED">马上抢</span>
<span v-else></span>
<button
:class="['ss-reset-button cart-btn', { disabled: activeTimeConfig?.status === TimeStatusEnum.END}]"
v-if="activeTimeConfig?.status === TimeStatusEnum.WAIT_START">
<span>未开始</span>
</button>
<button
:class="['ss-reset-button cart-btn', { disabled: activeTimeConfig?.status === TimeStatusEnum.END}]"
@click="sheep.$router.go('/pages/goods/seckill', { id: activity.id })"
v-else-if='activeTimeConfig?.status === TimeStatusEnum.STARTED'>
<span>马上抢</span>
</button>
<button
:class="['ss-reset-button cart-btn', { disabled: activeTimeConfig?.status === TimeStatusEnum.END}]"
v-else>
<span>已结束</span>
</button>
</template>
</s-goods-column>
</view>
<uni-load-more
v-if="activityTotal > 0"
:status="loadStatus"
:content-text="{
<uni-load-more v-if="activityTotal > 0" :status="loadStatus" :content-text="{
contentdown: '上拉加载更多',
}"
@tap="loadMore"
/>
}" @tap="loadMore" />
</scroll-view>
</view>
</s-layout>
</template>
<script setup>
import {reactive, computed, ref, nextTick} from 'vue';
import { onLoad, onReachBottom } from '@dcloudio/uni-app';
import {
reactive,
computed,
ref,
nextTick
} from 'vue';
import {
onLoad,
onReachBottom
} from '@dcloudio/uni-app';
import sheep from '@/sheep';
import { useDurationTime } from '@/sheep/hooks/useGoods';
import {
useDurationTime
} from '@/sheep/hooks/useGoods';
import SeckillApi from "@/sheep/api/promotion/seckill";
import dayjs from "dayjs";
import {TimeStatusEnum} from "@/sheep/util/const";
import {
TimeStatusEnum
} from "@/sheep/util/const";
//
const { safeAreaInsets, safeArea } = sheep.$platform.device;
const {
safeAreaInsets,
safeArea
} = sheep.$platform.device;
const statusBarHeight = sheep.$platform.device.statusBarHeight * 2;
const pageHeight = (safeArea.height + safeAreaInsets.bottom) * 2 + statusBarHeight - sheep.$platform.navbar - 350;
const headerBg = sheep.$url.css('/static/img/shop/goods/seckill-header.png');
//
const goodsFields = {
name: { show: true },
introduction: { show: true },
price: { show: true },
marketPrice: { show: true },
name: {
show: true
},
introduction: {
show: true
},
price: {
show: true
},
marketPrice: {
show: true
},
};
//#region
@ -127,25 +143,32 @@
const timeConfigList = ref([])
//
const getSeckillConfigList = async () => {
const { data } = await SeckillApi.getSeckillConfigList()
const {
data
} = await SeckillApi.getSeckillConfigList()
const now = dayjs();
const today = now.format('YYYY-MM-DD')
const select = ref([])
//
data.forEach((config, index) => {
const startTime = dayjs(`${today} ${config.startTime}`)
const endTime = dayjs(`${today} ${config.endTime}`)
select.value[index] = config.id;
if (now.isBefore(startTime)) {
config.status = TimeStatusEnum.WAIT_START;
// select.value[index] = config.id;
} else if (now.isAfter(endTime)) {
config.status = TimeStatusEnum.END;
// select.value[index] = config.id;
} else {
config.status = TimeStatusEnum.STARTED;
activeTimeIndex.value = index;
// select.value[index] = config.id;
activeTimeIndex.value = index
}
})
timeConfigList.value = data
//
handleChangeTimeConfig(activeTimeIndex.value);
handleChangeTimeConfig(activeTimeIndex.value, select.value[activeTimeIndex.value]);
//
scrollToTimeConfig(activeTimeIndex.value)
}
@ -159,11 +182,12 @@
//
const activeTimeIndex = ref(0) //
const activeTimeConfig = computed(() => timeConfigList.value[activeTimeIndex.value]) //
const handleChangeTimeConfig = (index) => {
const handleChangeTimeConfig = (index, id) => {
activeTimeIndex.value = index
//
activityPageParams.pageNo = 1
activityPageParams.configId = id;
activityList.value = []
getActivityList();
}
@ -182,7 +206,7 @@
//
const activityPageParams = reactive({
id: 0, // ID
configId: 0, // ID
pageNo: 1, //
pageSize: 5, //
})
@ -191,7 +215,9 @@
const loadStatus = ref('') //
async function getActivityList() {
loadStatus.value = 'loading';
const { data } = await SeckillApi.getSeckillActivityPage(activityPageParams)
const {
data
} = await SeckillApi.getSeckillActivityPage(activityPageParams)
data.list.forEach(activity => {
//
activity.percent = parseInt(100 * (activity.totalStock - activity.stock) / activity.totalStock);
@ -235,6 +261,7 @@
margin: -276rpx auto 0 auto;
border-radius: 14rpx;
overflow: hidden;
swiper {
height: 330rpx !important;
border-radius: 14rpx;
@ -246,6 +273,7 @@
height: 100%;
border-radius: 14rpx;
overflow: hidden;
img {
border-radius: 14rpx;
}
@ -257,10 +285,12 @@
width: 75rpx;
height: 70rpx;
}
//
.time-list {
width: 596rpx;
white-space: nowrap;
//
.item {
display: inline-block;
@ -270,17 +300,20 @@
box-sizing: border-box;
margin-right: 30rpx;
width: 130rpx;
//
.time {
font-size: 36rpx;
font-weight: 600;
color: #333;
}
//
&.active {
.time {
color: var(--ui-BG-Main);
}
//
.status {
height: 30rpx;
@ -301,6 +334,7 @@
margin: 0 20rpx 0 20rpx;
background: #fff;
border-radius: 20rpx 20rpx 0 0;
.content-header {
width: 100%;
border-radius: 20rpx 20rpx 0 0;
@ -312,6 +346,7 @@
height: 64rpx;
background: rgba($color: #fff, $alpha: 0.66);
border-radius: 32px;
//
.countdown-title {
font-size: 28rpx;
@ -319,10 +354,12 @@
color: #333333;
line-height: 28rpx;
}
//
.countdown-time {
font-size: 28rpx;
color: rgba(#ed3c30, 0.23);
//
.countdown-h {
font-size: 24rpx;
@ -334,6 +371,7 @@
background: rgba(#ed3c30, 0.23);
border-radius: 6rpx;
}
//
.countdown-num {
font-size: 24rpx;
@ -348,12 +386,15 @@
}
}
}
//
.scroll-box {
height: 900rpx;
//
.goods-box {
position: relative;
//
.cart-btn {
position: absolute;
@ -373,6 +414,7 @@
color: #fff;
}
}
//
.limit {
font-size: 22rpx;

View File

@ -36,7 +36,7 @@
<text v-else>
{{
state.coupon.status === 1
? '立即使用'
? '使用'
: state.coupon.status === 2
? '已使用'
: '已过期'

View File

@ -7,30 +7,47 @@
<!-- 骨架屏 -->
<detailSkeleton v-if="state.skeletonLoading" />
<!-- 下架/售罄提醒 -->
<s-empty
v-else-if="state.goodsInfo === null"
text="商品不存在或已下架"
icon="/static/soldout-empty.png"
showAction
actionText="再逛逛"
actionUrl="/pages/goods/list"
/>
<s-empty v-else-if="state.goodsInfo === null" text="商品不存在或已下架" icon="/static/soldout-empty.png" showAction
actionText="再逛逛" 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"
/>
<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="discount" v-if="setShow">
<image class="disImg" src="../../static/images/dis.png"></image>
<view class="discountCont">
<view class="disContT">
<view class="disContT1">
<view class="disContT1P">
{{fen2yuan(settleData.price)}}
</view>
<view class="disContT1End">
直降{{fen2yuan( state.goodsInfo.price - settleData.price)}}
</view>
</view>
<view class="disContT2">
限时折扣
</view>
</view>
<view class="disContB">
<view class="disContB1">
价格{{fen2yuan(state.goodsInfo.price)}} 剩余{{settleData.stock}}
</view>
<view class="disContB2">
距结束仅剩
<countDown :tipText="' '" :bgColor="bgColor" :dayText="':'" :hourText="':'"
:minuteText="':'" :secondText="' '" :datatime="settleData.endTime / 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="ss-flex ss-row-between ss-col-center ss-m-b-26" v-if="!setShow">
<view class="price-box ss-flex ss-col-bottom">
<view class="price-text ss-m-r-16">
{{ fen2yuan(state.selectedSku.price || state.goodsInfo.price) }}
@ -47,23 +64,16 @@
<!-- 满减送/限时折扣活动的提示 -->
<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"
>
<view class="tag ss-m-r-10" v-for="promos in state.activityInfo" :key="promos.id"
@tap="onActivity">
{{ promos.name }}
</view>
</view>
</div>
<!-- 优惠劵 -->
<view
class="get-coupon-box ss-flex ss-col-center ss-m-l-20"
@tap="state.showModel = true"
v-if="state.couponInfo.length"
>
<!-- 优惠劵@tap="state.showModel = true" -->
<view class="get-coupon-box ss-flex ss-col-center ss-m-l-20" @tap="onActivity"
v-if="state.couponInfo.length">
<view class="discounts-title ss-m-r-8">领券</view>
<text class="cicon-forward"></text>
</view>
@ -74,51 +84,30 @@
<!-- 功能卡片 -->
<view class="detail-cell-card detail-card ss-flex-col">
<detail-cell-sku
v-model="state.selectedSku.goods_sku_text"
:sku="state.selectedSku"
@tap="state.showSelectSku = true"
/>
<detail-cell-sku v-model="state.selectedSku.goods_sku_text" :sku="state.selectedSku"
@tap="state.showSelectSku = true" />
</view>
<!-- 规格与数量弹框 -->
<s-select-sku
:goodsInfo="state.goodsInfo"
:show="state.showSelectSku"
@addCart="onAddCart"
@buy="onBuy"
@change="onSkuChange"
@close="state.showSelectSku = false"
/>
<s-select-sku :goodsInfo="state.goodsInfo" :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-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 -->
<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">
<button
class="ss-reset-button add-btn ui-Shadow-Main"
@tap="state.showSelectSku = true"
>
<button class="ss-reset-button add-btn ui-Shadow-Main" @tap="state.showSelectSku = true">
加入购物车
</button>
<button
class="ss-reset-button buy-btn ui-Shadow-Main"
@tap="state.showSelectSku = true"
>
<button class="ss-reset-button buy-btn ui-Shadow-Main" @tap="state.showSelectSku = true">
立即购买
</button>
</view>
@ -128,32 +117,38 @@
</detail-tabbar>
<!-- 优惠劵弹窗 -->
<s-coupon-get
v-model="state.couponInfo"
:show="state.showModel"
@close="state.showModel = false"
@get="onGet"
/>
<!-- <s-coupon-get v-model="state.couponInfo" :show="state.showModel" @close="state.showModel = false"
@get="onGet" /> -->
<!-- 满减送/限时折扣活动弹窗 -->
<s-activity-pop
v-model="state.activityInfo"
:show="state.showActivityModel"
@close="state.showActivityModel = false"
/>
<s-activity-pop v-model="state" :show="state.showActivityModel"
@close="state.showActivityModel = false" @get="onGet" />
</block>
</s-layout>
</view>
</template>
<script setup>
import { reactive, computed } from 'vue';
import { onLoad, onPageScroll } from '@dcloudio/uni-app';
import {
reactive,
computed,
ref
} from 'vue';
import {
onLoad,
onPageScroll
} from '@dcloudio/uni-app';
import sheep from '@/sheep';
import CouponApi from '@/sheep/api/promotion/coupon';
import ActivityApi from '@/sheep/api/promotion/activity';
import FavoriteApi from '@/sheep/api/product/favorite';
import { formatSales, formatGoodsSwiper, fen2yuan } from '@/sheep/hooks/useGoods';
import {
formatSales,
formatGoodsSwiper,
fen2yuan,
handList,
handListPrice
} from '@/sheep/hooks/useGoods';
import detailNavbar from './components/detail/detail-navbar.vue';
import detailCellSku from './components/detail/detail-cell-sku.vue';
import detailTabbar from './components/detail/detail-tabbar.vue';
@ -161,11 +156,22 @@
import detailCommentCard from './components/detail/detail-comment-card.vue';
import detailContentCard from './components/detail/detail-content-card.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';
onPageScroll(() => {});
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,
@ -182,7 +188,13 @@
//
function onSkuChange(e) {
if (e.type == 4) {
settleData.value = e
setShow.value = true
} else {
state.selectedSku = e;
setShow.value = false
}
}
//
@ -196,21 +208,17 @@
//
function onBuy(e) {
if (!state.selectedSku.id) {
if (!e.id) {
sheep.$helper.toast('请选择商品规格');
return;
}
sheep.$router.go('/pages/order/confirm', {
data: JSON.stringify({
items: [
{
items: [{
skuId: e.id,
count: e.goods_num,
},
],
// TODO 2
deliveryType: 1,
pointStatus: false,
categoryId: state.goodsInfo.categoryId
}]
}),
});
}
@ -222,7 +230,9 @@
//
async function onGet(id) {
const { code } = await CouponApi.takeCoupon(id);
const {
code
} = await CouponApi.takeCoupon(id);
if (code !== 0) {
return;
}
@ -237,8 +247,7 @@
// TODO
const shareInfo = computed(() => {
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),
desc: state.goodsInfo.introduction,
@ -246,24 +255,58 @@
page: '2',
query: state.goodsInfo.id,
},
},
{
}, {
type: 'goods', //
title: state.goodsInfo.name, //
image: sheep.$url.cdn(state.goodsInfo.picUrl), //
price: fen2yuan(state.goodsInfo.price), //
original_price: fen2yuan(state.goodsInfo.marketPrice), //
},
);
});
});
async function getCoupon() {
const { code, data } = await CouponApi.getCouponTemplateList(state.goodsId, 2, 10);
const {
code,
data
} = await CouponApi.getCouponTemplateList(state.goodsId, 2, 10);
if (code === 0) {
state.couponInfo = data;
}
}
//
const setShow = ref(false)
const settleData = ref()
async function getSettlementByIds(ids) {
const { data } = await SpuApi.getSettlementProduct(ids);
settleData.value = handle(data)
state.goodsInfo.skus = handListPrice(state.goodsInfo.skus, data[0].skus)
}
//
function handle(array) {
let setList = {}
array.some(item => {
return item.skus.some(items => {
if (items.type === 4) {
setShow.value = true;
setList = items;
return true; // truesome
}
return false; //
});
});
//
state.goodsInfo.skus.forEach(item => {
if (item.id == setList.skuId) {
setList.stock = item.stock
}
})
return setList
}
onLoad((options) => {
//
if (!options.id) {
@ -281,7 +324,6 @@
//
state.skeletonLoading = false;
state.goodsInfo = res.data;
//
if (isLogin.value) {
FavoriteApi.isFavoriteExists(state.goodsId, 'goods').then((res) => {
@ -301,19 +343,19 @@
if (res.code !== 0) {
return;
}
res.data.forEach((activity) => {
if ([1, 2, 3].includes(activity.type)) {
// //
let activData = handList(res.data)
activData.forEach(activity => {
if ([1, 2, 3].includes(activity.type)) { // //
state.activityList.push(activity);
} else if (activity.type === 5) {
//
} else if (activity.type === 5) { //
state.activityInfo.push(activity);
} else {
// TODO
console.log('待实现!优先级不高');
} else { // TODO
// console.log('');
}
})
});
});
//
getSettlementByIds(state.goodsId)
});
</script>
@ -462,4 +504,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: .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>

View File

@ -118,7 +118,7 @@
</template>
<script setup>
import { reactive } from 'vue';
import { reactive,ref } from 'vue';
import { onLoad, onReachBottom } from '@dcloudio/uni-app';
import sheep from '@/sheep';
import _ from 'lodash-es';
@ -277,7 +277,15 @@
if (code !== 0) {
return;
}
state.pagination.list = _.concat(state.pagination.list, data.list);
// 使 map id
const ids = data.list.map(item => item.id);
// 使 join id
const idsString = ids.join(',');
//
settleData.value = await getSettlementByIds(idsString)
//
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';
mountMasonry();
@ -292,6 +300,55 @@
getList(state.currentSort, state.currentOrder);
}
//
const settleData = ref()
async function getSettlementByIds(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 }]));
// array
array.forEach(item => {
// discountPrice vipPrice null
let discountPrice = null;
let vipPrice = null;
let foundType4 = false;
let foundType6 = false;
// skus type 4 6
item.skus.forEach(sku => {
if (!foundType4 && sku.type === 4) {
discountPrice = sku.price;
foundType4 = true;
}
if (!foundType6 && sku.type === 6) {
vipPrice = sku.price;
foundType6 = true;
}
// type 4 6
if (foundType4 && foundType6) {
return;
}
});
// dataMap
if (dataMap.has(item.id)) {
dataMap.get(item.id).discountPrice = discountPrice;
dataMap.get(item.id).vipPrice = vipPrice;
dataMap.get(item.id).reward = item.reward;
}
});
//
return Array.from(dataMap.values());
}
onLoad((options) => {
state.categoryId = options.categoryId;
state.keyword = options.keyword;

View File

@ -6,26 +6,13 @@
<!-- 骨架屏 -->
<detailSkeleton v-if="state.skeletonLoading" />
<!-- 下架/售罄提醒 -->
<s-empty
v-else-if="state.goodsInfo === null || state.goodsInfo.activity_type !== 'seckill'"
text="活动不存在或已结束"
icon="/static/soldout-empty.png"
showAction
actionText="再逛逛"
actionUrl="/pages/goods/list"
/>
<s-empty v-else-if="state.goodsInfo === null || state.goodsInfo.activity_type !== 'seckill'" text="活动不存在或已结束"
icon="/static/soldout-empty.png" showAction actionText="再逛逛" actionUrl="/pages/goods/list" />
<block v-else>
<view class="detail-swiper-selector">
<!-- 商品图轮播 -->
<su-swiper
class="ss-m-b-14"
isPreview
:list="state.goodsSwiper"
dotStyle="tag"
imageMode="widthFix"
dotCur="bg-mask-40"
:seizeHeight="750"
/>
<su-swiper class="ss-m-b-14" isPreview :list="state.goodsSwiper" dotStyle="tag" imageMode="widthFix"
dotCur="bg-mask-40" :seizeHeight="750" />
<!-- 价格+标题 -->
<view class="title-card ss-m-y-14 ss-m-x-20 ss-p-x-20 ss-p-y-34">
@ -63,7 +50,7 @@
<detail-progress :percent="state.percent" />
</view>
<view class="title-text ss-line-2 ss-m-b-6">{{ state.goodsInfo?.name }}</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>
@ -72,14 +59,9 @@
<detail-cell-sku :sku="state.selectedSku" @tap="state.showSelectSku = true" />
</view>
<!-- 规格与数量弹框 -->
<s-select-seckill-sku
v-model="state.goodsInfo"
:show="state.showSelectSku"
:single-limit-count="activity.singleLimitCount"
@buy="onBuy"
@change="onSkuChange"
@close="state.showSelectSku = false"
/>
<s-select-seckill-sku v-model="state.goodsInfo" :show="state.showSelectSku"
:single-limit-count="activity.singleLimitCount" @buy="onBuy" @change="onSkuChange"
@close="state.showSelectSku = false" />
</view>
<!-- 评价 -->
@ -91,36 +73,25 @@
<detail-tabbar v-model="state.goodsInfo">
<!-- TODO: 缺货中 已售罄 判断 设计-->
<view class="buy-box ss-flex ss-col-center ss-p-r-20">
<button
class="ss-reset-button origin-price-btn ss-flex-col"
v-if="state.goodsInfo.marketPrice"
@tap="sheep.$router.go('/pages/goods/index', { id: state.goodsInfo.id })"
>
<button class="ss-reset-button origin-price-btn ss-flex-col" v-if="state.goodsInfo.marketPrice"
@tap="sheep.$router.go('/pages/goods/index', { id: state.goodsInfo.id })">
<view>
<view class="btn-price">{{ fen2yuan(state.goodsInfo.marketPrice) }}</view>
<view>原价购买</view>
</view>
</button>
<button v-else class="ss-reset-button origin-price-btn ss-flex-col">
<view
class="no-original"
:class="
<view class="no-original" :class="
state.goodsInfo.stock === 0 || timeStatusEnum !== TimeStatusEnum.STARTED ? '' : ''
"
>
">
秒杀价
</view>
</button>
<button
class="ss-reset-button btn-box ss-flex-col"
@tap="state.showSelectSku = true"
:class="
<button class="ss-reset-button btn-box ss-flex-col" @tap="state.showSelectSku = true" :class="
timeStatusEnum === TimeStatusEnum.STARTED && state.goodsInfo.stock != 0
? 'check-btn-box'
: 'disabled-btn-box'
"
:disabled="state.goodsInfo.stock === 0 || timeStatusEnum !== TimeStatusEnum.STARTED"
>
" :disabled="state.goodsInfo.stock === 0 || timeStatusEnum !== TimeStatusEnum.STARTED">
<view class="btn-price">{{ fen2yuan(state.goodsInfo.price) }}</view>
<view v-if="timeStatusEnum === TimeStatusEnum.STARTED">
<view v-if="state.goodsInfo.stock === 0"></view>
@ -135,11 +106,26 @@
</template>
<script setup>
import { reactive, computed, ref } from 'vue';
import { onLoad, onPageScroll } from '@dcloudio/uni-app';
import {
reactive,
computed,
ref,
unref
} from 'vue';
import {
onLoad,
onPageScroll
} from '@dcloudio/uni-app';
import sheep from '@/sheep';
import { isEmpty, min } from 'lodash-es';
import { useDurationTime, formatGoodsSwiper, fen2yuan } from '@/sheep/hooks/useGoods';
import {
isEmpty,
min
} from 'lodash-es';
import {
useDurationTime,
formatGoodsSwiper,
fen2yuan
} from '@/sheep/hooks/useGoods';
import detailNavbar from './components/detail/detail-navbar.vue';
import detailCellSku from './components/detail/detail-cell-sku.vue';
import detailTabbar from './components/detail/detail-tabbar.vue';
@ -149,7 +135,10 @@
import detailProgress from './components/detail/detail-progress.vue';
import SeckillApi from '@/sheep/api/promotion/seckill';
import SpuApi from '@/sheep/api/product/spu';
import { getTimeStatusEnum, TimeStatusEnum } from '@/sheep/util/const';
import {
getTimeStatusEnum,
TimeStatusEnum
} from '@/sheep/util/const';
const headerBg = sheep.$url.css('/static/img/shop/goods/seckill-bg.png');
const btnBg = sheep.$url.css('/static/img/shop/goods/seckill-btn.png');
@ -186,53 +175,53 @@
order_type: 'goods',
buy_type: 'seckill',
seckillActivityId: activity.value.id,
items: [
{
items: [{
skuId: sku.id,
count: sku.count,
},
],
}, ],
}),
});
}
// TODO
//
const shareInfo = computed(() => {
if (isEmpty(activity)) return {};
return sheep.$platform.share.getShareInfo(
{
if (isEmpty(unref(activity))) return {};
return sheep.$platform.share.getShareInfo({
title: activity.value.name,
image: sheep.$url.cdn(state.goodsInfo.picUrl),
params: {
page: '4',
query: activity.value.id,
},
},
{
}, {
type: 'goods', //
title: activity.value.name, //
image: sheep.$url.cdn(state.goodsInfo.picUrl), //
price: state.goodsInfo.price, //
marketPrice: state.goodsInfo.marketPrice, //
},
);
}, );
});
const activity = ref();
const timeStatusEnum = ref('');
//
const getActivity = async (id) => {
const { data } = await SeckillApi.getSeckillActivity(id);
const {
data
} = await SeckillApi.getSeckillActivity(id);
activity.value = data;
timeStatusEnum.value = getTimeStatusEnum(activity.startTime, activity.endTime);
timeStatusEnum.value = getTimeStatusEnum(activity.value.startTime, activity.value.endTime);
state.percent = 100 - data.stock / data.totalStock * 100;
//
await getSpu(data.spuId);
};
//
const getSpu = async (id) => {
const { data } = await SpuApi.getSpuDetail(id);
//
const {
data
} = await SpuApi.getSpuDetail(id);
data.activity_type = 'seckill';
state.goodsInfo = data;
//
@ -283,6 +272,7 @@
.disabled-btn-box[disabled] {
background-color: transparent;
}
.detail-card {
background-color: $white;
margin: 14rpx 20rpx;
@ -373,6 +363,7 @@
font-size: 26rpx;
font-weight: 500;
color: #ffffff;
.countdown-h {
font-size: 24rpx;
font-family: OPPOSANS;
@ -383,6 +374,7 @@
background: rgba(#000000, 0.1);
border-radius: 6rpx;
}
.countdown-num {
font-size: 24rpx;
font-family: OPPOSANS;
@ -466,6 +458,7 @@
line-height: normal;
border-radius: 0px 40rpx 40rpx 0px;
}
.btn-price {
font-family: OPPOSANS;
@ -483,6 +476,7 @@
line-height: normal;
font-size: 24rpx;
font-weight: 500;
.no-original {
font-size: 28rpx;
}

View File

@ -0,0 +1,263 @@
<!-- 下单界面收货地址 or 自提门店的选择组件 -->
<template>
<view class="allAddress" :style="state.isPickUp ? '':'padding-top:10rpx;'">
<view class="nav flex flex-wrap">
<view class="item font-color" :class="state.deliveryType === 1 ? 'on' : 'on2'"
@tap="switchDeliveryType(1)" v-if='state.isPickUp' />
<view class="item font-color" :class="state.deliveryType === 2 ? 'on' : 'on2'"
@tap="switchDeliveryType(2)" v-if='state.isPickUp' />
</view>
<!-- 情况一收货地址的选择 -->
<view class='address flex flex-wrap flex-center ss-row-between' @tap='onSelectAddress' v-if='state.deliveryType === 1'
:style="state.isPickUp ? '':'border-top-left-radius: 14rpx;border-top-right-radius: 14rpx;'">
<view class='addressCon' v-if="state.addressInfo.name">
<view class='name'>{{ state.addressInfo.name }}
<text class='phone'>{{ state.addressInfo.mobile }}</text>
</view>
<view class="flex flex-wrap">
<text class='default font-color' v-if="state.addressInfo.defaultStatus">[]</text>
<text class="line2">{{ state.addressInfo.areaName }} {{ state.addressInfo.detailAddress }}</text>
</view>
</view>
<view class='addressCon' v-else>
<view class='setaddress'>设置收货地址</view>
</view>
<view class='iconfont'>
<view class="ss-rest-button">
<text class="_icon-forward" />
</view>
</view>
</view>
<!-- 情况二门店的选择 -->
<view class='address flex flex-wrap flex-center ss-row-between' v-else @tap="onSelectAddress">
<view class='addressCon' v-if="state.pickUpInfo.name">
<view class='name'>{{ state.pickUpInfo.name }}
<text class='phone'>{{ state.pickUpInfo.phone }}</text>
</view>
<view class="line1"> {{ state.pickUpInfo.areaName }}{{ ', ' + state.pickUpInfo.detailAddress }}
</view>
</view>
<view class='addressCon' v-else>
<view class='setaddress'>选择自提门店</view>
</view>
<view class='iconfont'>
<view class="ss-rest-button">
<text class="_icon-forward" />
</view>
</view>
</view>
<view class='line'>
<image :src="sheep.$url.static('/static/images/line.png', 'local')" />
</view>
</view>
</template>
<script setup>
import { computed } from 'vue';
import sheep from '@/sheep';
import { isEmpty } from 'lodash-es';
const props = defineProps({
modelValue: {
type: Object,
default() {},
}
});
const emits = defineEmits(['update:modelValue','change']);
// computed
const state = computed({
get(){
return new Proxy(props.modelValue, {
set(obj, name, val) {
emits('update:modelValue', {
...obj,
[name]: val,
});
return true;
}
})
},
set(val){
emits('update:modelValue', val);
}
})
//
function onSelectAddress() {
let emitName = 'SELECT_ADDRESS'
let addressPage = '/pages/user/address/list?type=select';
if (state.value.deliveryType === 2){
emitName = 'SELECT_PICK_UP_INFO'
addressPage = '/pages/user/goods_details_store/index'
}
uni.$once(emitName, (e) => {
changeConsignee(e.addressInfo);
});
sheep.$router.go(addressPage);
}
// &
async function changeConsignee(addressInfo = {}) {
if (!isEmpty(addressInfo)) {
if (state.value.deliveryType === 1){
state.value.addressInfo = addressInfo;
}
if (state.value.deliveryType === 2){
state.value.pickUpInfo = addressInfo;
}
emits('change')
}
}
//
const switchDeliveryType = (type) =>{
state.value.deliveryType = type;
emits('change')
}
</script>
<style scoped lang="scss">
.allAddress .font-color{
color: #E93323!important
}
.line2{
width: 504rpx;
}
.textR {
text-align: right;
}
.line {
width: 100%;
height: 3rpx;
}
.line image {
width: 100%;
height: 100%;
display: block;
}
.address {
padding: 28rpx;
background-color: #fff;
box-sizing: border-box;
}
.address .addressCon {
width: 596rpx;
font-size: 26rpx;
color: #666;
}
.address .addressCon .name {
font-size: 30rpx;
color: #282828;
font-weight: bold;
margin-bottom: 10rpx;
}
.address .addressCon .name .phone {
margin-left: 50rpx;
}
.address .addressCon .default {
margin-right: 12rpx;
}
.address .addressCon .setaddress {
color: #333;
font-size: 28rpx;
}
.address .iconfont {
font-size: 35rpx;
color: #707070;
}
.allAddress {
width: 100%;
background: linear-gradient(to bottom, #e93323 0%, #f5f5f5 100%);
// background-image: linear-gradient(to bottom, #e93323 0%, #f5f5f5 100%);
// background-image: -webkit-linear-gradient(to bottom, #e93323 0%, #f5f5f5 100%);
// background-image: -moz-linear-gradient(to bottom, #e93323 0%, #f5f5f5 100%);
//padding: 100rpx 30rpx 0 30rpx;
padding-top: 100rpx;
padding-bottom: 10rpx;
}
.allAddress .nav {
width: 690rpx;
margin: 0 auto;
}
.allAddress .nav .item {
width: 334rpx;
}
.allAddress .nav .item.on {
position: relative;
width: 230rpx;
}
.allAddress .nav .item.on::before {
position: absolute;
bottom: 0;
content: "快递配送";
font-size: 28rpx;
display: block;
height: 0;
width: 336rpx;
border-width: 0 20rpx 80rpx 0;
border-style: none solid solid;
border-color: transparent transparent #fff;
z-index: 2;
border-radius: 14rpx 36rpx 0 0;
text-align: center;
line-height: 80rpx;
}
.allAddress .nav .item:nth-of-type(2).on::before {
content: "到店自提";
border-width: 0 0 80rpx 20rpx;
border-radius: 36rpx 14rpx 0 0;
}
.allAddress .nav .item.on2 {
position: relative;
}
.allAddress .nav .item.on2::before {
position: absolute;
bottom: 0;
content: "到店自提";
font-size: 28rpx;
display: block;
height: 0;
width: 401rpx;
border-width: 0 0 60rpx 60rpx;
border-style: none solid solid;
border-color: transparent transparent #f7c1bd;
border-radius: 36rpx 14rpx 0 0;
text-align: center;
line-height: 60rpx;
}
.allAddress .nav .item:nth-of-type(1).on2::before {
content: "快递配送";
border-width: 0 60rpx 60rpx 0;
border-radius: 14rpx 36rpx 0 0;
}
.allAddress .address {
width: 690rpx;
max-height: 180rpx;
margin: 0 auto;
}
.allAddress .line {
width: 100%;
margin: 0 auto;
}
</style>

View File

@ -1,36 +1,18 @@
<template>
<s-layout title="确认订单">
<!-- TODO这个判断先删除 v-if="state.orderInfo.need_address === 1" -->
<view class="bg-white address-box ss-m-b-14 ss-r-b-10" @tap="onSelectAddress">
<s-address-item :item="state.addressInfo" :hasBorderBottom="false">
<view class="ss-rest-button">
<text class="_icon-forward" />
</view>
</s-address-item>
</view>
<!-- 头部地址选择配送地址自提地址 -->
<AddressSelection v-model="addressState" @change="getOrderInfo()" />
<!-- 商品信息 -->
<view class="order-card-box ss-m-b-14">
<s-goods-item
v-for="item in state.orderInfo.items"
:key="item.skuId"
:img="item.picUrl"
:title="item.spuName"
:skuText="item.properties.map((property) => property.valueName).join(' ')"
:price="item.price"
:num="item.count"
marginBottom="10"
/>
<s-goods-item v-for="item in state.orderInfo.items" :key="item.skuId" :img="item.picUrl"
:title="item.spuName" :skuText="item.properties.map((property) => property.valueName).join(' ')"
:price="item.price" :num="item.count" marginBottom="10" />
<view class="order-item ss-flex ss-col-center ss-row-between ss-p-x-20 bg-white ss-r-10">
<view class="item-title">订单备注</view>
<view class="ss-flex ss-col-center">
<uni-easyinput
maxlength="20"
placeholder="建议留言前先与商家沟通"
v-model="state.orderPayload.remark"
:inputBorder="false"
:clearable="false"
/>
<uni-easyinput maxlength="20" placeholder="建议留言前先与商家沟通" v-model="state.orderPayload.remark"
:inputBorder="false" :clearable="false" />
</view>
</view>
</view>
@ -46,67 +28,71 @@
</text>
</view>
</view>
<!-- TODO 芋艿接入积分 -->
<view
class="order-item ss-flex ss-col-center ss-row-between"
v-if="state.orderPayload.order_type === 'score'"
>
<view class="item-title">扣除积分</view>
<view class="order-item ss-flex ss-col-center ss-row-between" v-if="state.orderInfo.type === 0">
<view class="item-title">积分抵扣</view>
<view class="ss-flex ss-col-center">
<image
:src="sheep.$url.static('/static/img/shop/goods/score1.svg')"
class="score-img"
/>
<text class="item-value ss-m-r-24">{{ state.orderInfo.score_amount }}</text>
{{ state.pointStatus ? '剩余积分' : '当前积分' }}
<image :src="sheep.$url.static('/static/img/shop/goods/score1.svg')" class="score-img" />
<text class="item-value ss-m-r-24">
{{ state.pointStatus ? state.orderInfo.totalPoint - state.orderInfo.usePoint : (state.orderInfo.totalPoint || 0) }}
</text>
<checkbox-group @change="changeIntegral">
<checkbox :checked='state.pointStatus'
:disabled="!state.orderInfo.totalPoint || state.orderInfo.totalPoint <= 0" />
</checkbox-group>
</view>
</view>
<view class="order-item ss-flex ss-col-center ss-row-between">
<!-- 快递配置时信息的展示 -->
<view class="order-item ss-flex ss-col-center ss-row-between" v-if='addressState.deliveryType === 1'>
<view class="item-title">运费</view>
<view class="ss-flex ss-col-center">
<text class="item-value ss-m-r-24">
<text class="item-value ss-m-r-24" v-if="state.orderInfo.price.deliveryPrice > 0">
+{{ fen2yuan(state.orderInfo.price.deliveryPrice) }}
</text>
<view class='item-value ss-m-r-24' v-else></view>
</view>
</view>
<!-- 门店自提时需要填写姓名和手机号 -->
<view class="order-item ss-flex ss-col-center ss-row-between" v-if='addressState.deliveryType === 2'>
<view class="item-title">联系人</view>
<view class="ss-flex ss-col-center">
<uni-easyinput maxlength="20" placeholder="请填写您的联系姓名" v-model="addressState.receiverName"
:inputBorder="false" :clearable="false" />
</view>
</view>
<view class="order-item ss-flex ss-col-center ss-row-between" v-if='addressState.deliveryType === 2'>
<view class="item-title">联系电话</view>
<view class="ss-flex ss-col-center">
<uni-easyinput maxlength="20" placeholder="请填写您的联系电话" v-model="addressState.receiverMobile"
:inputBorder="false" :clearable="false" />
</view>
</view>
<!-- 优惠劵只有 type = 0 普通订单非拼团秒杀砍价才可以使用优惠劵 -->
<view
class="order-item ss-flex ss-col-center ss-row-between"
v-if="state.orderInfo.type === 0"
>
<view class="order-item ss-flex ss-col-center ss-row-between" v-if="state.orderInfo.type === 0">
<view class="item-title">优惠券</view>
<view class="ss-flex ss-col-center" @tap="state.showCoupon = true">
<text class="item-value text-red" v-if="state.orderPayload.couponId > 0">
-{{ fen2yuan(state.orderInfo.price.couponPrice) }}
</text>
<text
class="item-value"
:class="state.couponInfo.length > 0 ? 'text-red' : 'text-disabled'"
v-else
>
<text class="item-value" :class="couponNumber > 0 ? 'text-red' : 'text-disabled'" v-else>
{{
state.couponInfo.length > 0 ? state.couponInfo.length + ' 张可用' : '暂无可用优惠券'
couponNumber > 0 ? couponNumber + ' 张可用' : '暂无可用优惠券'
}}
</text>
<text class="_icon-forward item-icon" />
</view>
</view>
<view
class="order-item ss-flex ss-col-center ss-row-between"
v-if="state.orderInfo.price.discountPrice > 0"
>
<view class="order-item ss-flex ss-col-center ss-row-between"
v-if="state.orderInfo.price.discountPrice > 0">
<view class="item-title">活动优惠</view>
<view class="ss-flex ss-col-center">
<!-- @tap="state.showDiscount = true" TODO 芋艿后续要把优惠信息打进去 -->
<view class="ss-flex ss-col-center" @tap="state.showDiscount = true">
<text class="item-value text-red">
-{{ fen2yuan(state.orderInfo.price.discountPrice) }}
</text>
<text class="_icon-forward item-icon" />
</view>
</view>
<view
class="order-item ss-flex ss-col-center ss-row-between"
v-if="state.orderInfo.price.vipPrice > 0"
>
<view class="order-item ss-flex ss-col-center ss-row-between" v-if="state.orderInfo.price.vipPrice > 0">
<view class="item-title">会员优惠</view>
<view class="ss-flex ss-col-center">
<text class="item-value text-red">
@ -125,19 +111,11 @@
</view>
<!-- 选择优惠券弹框 -->
<s-coupon-select
v-model="state.couponInfo"
:show="state.showCoupon"
@confirm="onSelectCoupon"
@close="state.showCoupon = false"
/>
<s-coupon-select v-model="state.couponInfo" :show="state.showCoupon" @confirm="onSelectCoupon"
@close="state.showCoupon = false" />
<!-- 满额折扣弹框 TODO 芋艿后续要把优惠信息打进去 -->
<s-discount-list
v-model="state.orderInfo"
:show="state.showDiscount"
@close="state.showDiscount = false"
/>
<s-discount-list v-model="state.orderInfo" :show="state.showDiscount" @close="state.showDiscount = false" />
<!-- 底部 -->
<su-fixed bottom :opacity="false" bg="bg-white" placeholder :noFixed="false" :index="200">
@ -147,10 +125,7 @@
{{ fen2yuan(state.orderInfo.price.payPrice) }}
</view>
</view>
<button
class="ss-reset-button ui-BG-Main-Gradient ss-r-40 submit-btn ui-Shadow-Main"
@tap="onConfirm"
>
<button class="ss-reset-button ui-BG-Main-Gradient ss-r-40 submit-btn ui-Shadow-Main" @tap="onConfirm">
提交订单
</button>
</view>
@ -159,14 +134,20 @@
</template>
<script setup>
import { reactive } from 'vue';
import { onLoad } from '@dcloudio/uni-app';
import {
reactive,
ref
} from 'vue';
import {
onLoad
} from '@dcloudio/uni-app';
import AddressSelection from '@/pages/order/addressSelection.vue';
import sheep from '@/sheep';
import { isEmpty } from 'lodash-es';
import OrderApi from '@/sheep/api/trade/order';
import CouponApi from '@/sheep/api/promotion/coupon';
import { fen2yuan } from '@/sheep/hooks/useGoods';
import { WxaSubscribeTemplate } from '@/sheep/util/const';
import {
fen2yuan
} from '@/sheep/hooks/useGoods';
const state = reactive({
orderPayload: {},
@ -174,27 +155,30 @@
items: [], //
price: {}, //
},
addressInfo: {}, //
showCoupon: false, //
couponInfo: [], //
showDiscount: false, //
// ========== ==========
pointStatus: false, //使
});
//
function onSelectAddress() {
uni.$once('SELECT_ADDRESS', (e) => {
changeConsignee(e.addressInfo);
const addressState = ref({
addressInfo: {}, //
deliveryType: 1, // 1 - 2 -
isPickUp: true, // TODO puhui999:
pickUpInfo: {}, //
receiverName: '', //
receiverMobile: '', //
});
sheep.$router.go('/pages/user/address/list');
}
// &
async function changeConsignee(addressInfo = {}) {
if (!isEmpty(addressInfo)) {
state.addressInfo = addressInfo;
}
// ========== ==========
/**
* 使用积分抵扣
*/
const changeIntegral = async () => {
state.pointStatus = !state.pointStatus;
await getOrderInfo();
}
};
//
async function onSelectCoupon(couponId) {
@ -205,22 +189,46 @@
//
function onConfirm() {
if (!state.addressInfo.id) {
if (addressState.value.deliveryType === 1 && !addressState.value.addressInfo.id) {
sheep.$helper.toast('请选择收货地址');
return;
}
if (addressState.value.deliveryType === 2) {
if (!addressState.value.pickUpInfo.id) {
sheep.$helper.toast('请选择自提门店地址');
return;
}
if (addressState.value.receiverName === '' || addressState.value.receiverMobile === '') {
sheep.$helper.toast('请填写联系人或联系人电话');
return;
}
if (!/^[\u4e00-\u9fa5\w]{2,16}$/.test(addressState.value.receiverName)) {
sheep.$helper.toast('请填写您的真实姓名');
return;
}
if (!/^1(3|4|5|7|8|9|6)\d{9}$/.test(addressState.value.receiverMobile)) {
sheep.$helper.toast('请填写正确的手机号');
return;
}
}
submitOrder();
}
// &
async function submitOrder() {
const { code, data } = await OrderApi.createOrder({
const {
code,
data
} = await OrderApi.createOrder({
items: state.orderPayload.items,
couponId: state.orderPayload.couponId,
remark: state.orderPayload.remark,
addressId: state.addressInfo.id,
deliveryType: 1, // TODO
pointStatus: false, // TODO
deliveryType: addressState.value.deliveryType,
addressId: addressState.value.addressInfo.id, //
pickUpStoreId: addressState.value.pickUpInfo.id, //
receiverName: addressState.value.receiverName, //
receiverMobile: addressState.value.receiverMobile, //
pointStatus: state.pointStatus,
combinationActivityId: state.orderPayload.combinationActivityId,
combinationHeadId: state.orderPayload.combinationHeadId,
seckillActivityId: state.orderPayload.seckillActivityId,
@ -242,29 +250,44 @@
// &
async function getOrderInfo() {
//
const { data, code } = await OrderApi.settlementOrder({
const {
data,
code
} = await OrderApi.settlementOrder({
items: state.orderPayload.items,
couponId: state.orderPayload.couponId,
addressId: state.addressInfo.id,
deliveryType: 1, // TODO
pointStatus: false, // TODO
deliveryType: addressState.value.deliveryType,
addressId: addressState.value.addressInfo.id, //
pickUpStoreId: addressState.value.pickUpInfo.id, //
receiverName: addressState.value.receiverName, //
receiverMobile: addressState.value.receiverMobile, //
pointStatus: state.pointStatus,
combinationActivityId: state.orderPayload.combinationActivityId,
combinationHeadId: state.orderPayload.combinationHeadId,
seckillActivityId: state.orderPayload.seckillActivityId,
});
if (code !== 0) {
setTimeout(() => {
uni.navigateBack({
delta: 1
})
}, 1500)
return;
}
state.orderInfo = data;
//
if (state.orderInfo.address) {
state.addressInfo = state.orderInfo.address;
addressState.value.addressInfo = state.orderInfo.address;
}
}
//
let couponNumber = ref(0)
async function getCoupons() {
const { code, data } = await CouponApi.getMatchCouponList(
const {
code,
data
} = await CouponApi.getMatchCouponList(
state.orderInfo.price.payPrice,
state.orderInfo.items.map((item) => item.spuId),
state.orderPayload.items.map((item) => item.skuId),
@ -272,6 +295,7 @@
);
if (code === 0) {
state.couponInfo = data;
couponNumber.value = state.couponInfo.filter(item => item.match).length;
}
}

View File

@ -13,6 +13,18 @@ const SpuApi = {
},
});
},
// 获得商品结算信息
getSettlementProduct: (ids) => {
return request({
url: '/trade/order/settlementProduct',
method: 'GET',
params: { ids },
custom: {
showLoading: false,
showError: false,
},
});
},
// 获得商品 SPU 分页
getSpuPage: (params) => {
return request({

View File

@ -2,34 +2,119 @@
<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>
<scroll-view
class="model-content ss-m-t-50"
scroll-y
:scroll-with-animation="false"
:enable-back-to-top="true"
>
<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="title ss-m-t-16 ss-m-l-20 ss-flex">优惠</view>
<view v-if="state.activityMap[state.activityInfo[0]?.id]?.reduc">
<view class="titleLi">促销</view>
<scroll-view class="model-content" scroll-y :scroll-with-animation="false" :enable-back-to-top="true">
<view class="actBox">
<view class="boxCont ss-flex ss-col-top ss-m-b-40" @tap="onGoodsList(state.activityInfo[0])">
<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="model-content-title">
<view class="contBu">
<text v-for="(item,index) in state.activityMap[state.activityInfo[0]?.id]?.reduc"
:key="index">{{fen2yuan(item.discountPrice)}}元减{{fen2yuan(item.limit)}};</text>
</view>
<view class="ss-m-b-24 cotBu-txt">
{{formatDateRange(state.activityInfo[0]?.startTime,state.activityInfo[0]?.endTime)}}
</view>
</view>
<text class="cicon-forward" />
</view>
</view>
<view class="actBox">
<view class="boxCont ss-flex ss-col-top ss-m-b-40" @tap="onGoodsList(state.activityInfo[0])">
<view class="model-content-tag ss-flex ss-row-center">包邮</view>
<view class="model-content-title">
<view class="contBu">
<text v-for="(item,index) in state.activityMap[state.activityInfo[0]?.id]?.ship"
:key="index" v-show="item.bull">{{fen2yuan(item.discountPrice)}}元包邮;</text>
</view>
<view class="ss-m-b-24 cotBu-txt">
{{formatDateRange(state.activityInfo[0]?.startTime,state.activityInfo[0]?.endTime)}}
</view>
</view>
<text class="cicon-forward" />
</view>
</view>
<view class="actBox">
<view class="boxCont ss-flex ss-col-top ss-m-b-40" @tap="onGoodsList(state.activityInfo[0])">
<view class="model-content-tag ss-flex ss-row-center">送积分</view>
<view class="model-content-title">
<view class="contBu">
<text v-for="(item,index) in state.activityMap[state.activityInfo[0]?.id]?.scor"
:key="index"
v-show="item.bull">{{fen2yuan(item.discountPrice)}}元送{{item.value}}积分;</text>
</view>
<view class="ss-m-b-24 cotBu-txt">
{{formatDateRange(state.activityInfo[0]?.startTime,state.activityInfo[0]?.endTime)}}
</view>
</view>
<text class="cicon-forward" />
</view>
</view>
<view class="actBox">
<view class="boxCont ss-flex ss-col-top ss-m-b-40" @tap="onGoodsList(state.activityInfo[0])">
<view class="model-content-tag ss-flex ss-row-center">送优惠券</view>
<view class="model-content-title">
<view class="contBu">
<text v-for="(item,index) in state.activityMap[state.activityInfo[0]?.id]?.cou"
:key="index"
v-show="item.bull">{{fen2yuan(item.discountPrice)}}元送{{item.value}}张优惠券;</text>
</view>
<view class="ss-m-b-24 cotBu-txt">
{{formatDateRange(state.activityInfo[0]?.startTime,state.activityInfo[0]?.endTime)}}
</view>
</view>
<text class="cicon-forward" />
</view>
</view>
</scroll-view>
</view>
<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 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?formatDateRange(item.validStartTime,item.validEndTime) : '领取后'+item.fixedStartTerm+'-'+item.fixedEndTerm +'天可用'}}
</view>
</view>
<view class="coupon" @click.stop="getBuy(item.id)" v-if="item.canTake">
立即领取
</view>
<view class="coupon2" v-else>
已领取
</view>
</view>
</view>
</scroll-view>
</view>
</su-popup>
</template>
<script setup>
import sheep from '@/sheep';
import { computed, reactive, watch } from 'vue';
import {
computed,
reactive,
watch
} from 'vue';
import RewardActivityApi from '@/sheep/api/promotion/rewardActivity';
import { formatRewardActivityRule } from '@/sheep/hooks/useGoods';
import {
fen2yuan,
formatDateRange,
handActitList
} from '@/sheep/hooks/useGoods';
const props = defineProps({
modelValue: {
type: Object,
@ -42,10 +127,10 @@
});
const emits = defineEmits(['close']);
const state = reactive({
activityInfo: computed(() => props.modelValue),
activityMap: {}
activityInfo: computed(() => props.modelValue.activityInfo),
activityMap: {},
couponInfo: computed(() => props.modelValue.couponInfo)
});
watch(
() => props.show,
() => {
@ -56,12 +141,16 @@
if (res.code !== 0) {
return;
}
state.activityMap[activity.id] = res.data;
state.activityMap[activity.id] = handActitList(res.data.rules);
})
});
}
},
);
//
const getBuy = (id) => {
emits('get', id);
};
function onGoodsList(e) {
sheep.$router.go('/pages/activity/index', {
@ -72,34 +161,141 @@
<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: 350rpx;
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;
}
</style>

View File

@ -1,23 +1,12 @@
<template>
<su-popup
:show="show"
type="bottom"
round="20"
@close="emits('close')"
showClose
backgroundColor="#f2f2f2"
>
<su-popup :show="show" type="bottom" round="20" @close="emits('close')" showClose backgroundColor="#f2f2f2">
<view class="model-box">
<view class="title ss-m-t-38 ss-m-l-20 ss-m-b-40">活动优惠</view>
<scroll-view
class="model-content ss-m-l-20"
scroll-y
:scroll-with-animation="false"
:enable-back-to-top="true"
>
<view v-for="(item, index) in state.orderInfo.promo_infos" :key="index">
<scroll-view class="model-content ss-m-l-20" scroll-y :scroll-with-animation="false"
:enable-back-to-top="true">
<view v-for="(item, index) in state.orderInfo.promotions" :key="index">
<view class="ss-flex ss-m-b-40 subtitle">
<view>{{ item.goods_ids.length }}</view>
<!-- <view>{{ item.goods_ids.length }}</view>
<view v-if="item.activity_type === 'full_discount'">
{{ item.discount_rule.full }}{{ item.discount_rule.discount }},已减
</view>
@ -25,15 +14,11 @@
<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>
<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 class="price-text">{{ item.promo_discount_money || '0.00' }}</view> -->
<view>
{{item.description}}
</view>
</view>
</scroll-view>
</view>
</scroll-view>
</view>
@ -43,8 +28,14 @@
</su-popup>
</template>
<script setup>
import { computed, reactive } from 'vue';
import {
computed,
reactive
} from 'vue';
import sheep from '@/sheep';
import {
fen2yuan
} from '@/sheep/hooks/useGoods';
const props = defineProps({
promoInfo: {
type: Array,
@ -67,28 +58,31 @@
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;
};
// 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 +91,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;
}

View File

@ -135,7 +135,7 @@
/**
* 商品卡片
*/
import { computed, reactive, onMounted } from 'vue';
import { computed, reactive, onMounted, ref } from 'vue';
import sheep from '@/sheep';
import SpuApi from '@/sheep/api/product/spu';
@ -227,10 +227,61 @@
return data;
}
//
const settleData = ref()
async function getSettlementByIds(ids) {
const { data } = await SpuApi.getSettlementProduct(ids);
return data;
}
//
async function enrichDataWithSkus(data, array) {
// id data
const dataMap = new Map(data.map(item => [item.id, { ...item }]));
// array
array.forEach(item => {
// discountPrice vipPrice null
let discountPrice = null;
let vipPrice = null;
let foundType4 = false;
let foundType6 = false;
// skus type 4 6
item.skus.forEach(sku => {
if (!foundType4 && sku.type === 4) {
discountPrice = sku.price;
foundType4 = true;
}
if (!foundType6 && sku.type === 6) {
vipPrice = sku.price;
foundType6 = true;
}
// type 4 6
if (foundType4 && foundType6) {
return;
}
});
// dataMap
if (dataMap.has(item.id)) {
dataMap.get(item.id).discountPrice = discountPrice;
dataMap.get(item.id).vipPrice = vipPrice;
dataMap.get(item.id).reward = item.reward;
}
});
//
return Array.from(dataMap.values());
}
//
onMounted(async () => {
//
state.goodsList = await getGoodsListByIds(spuIds.join(','));
const ms = await getGoodsListByIds(spuIds.join(','));
settleData.value = await getSettlementByIds(spuIds.join(','))
state.goodsList = await enrichDataWithSkus(ms,settleData.value)
//
if (layoutType === LayoutTypeEnum.TWO_COL){
//

View File

@ -2,38 +2,29 @@
<template>
<view class="ss-goods-wrap">
<!-- xs卡片横向紧凑型一行放两个图片左内容右边 -->
<view
v-if="size === 'xs'"
class="xs-goods-card ss-flex ss-col-stretch"
:style="[elStyles]"
@tap="onClick"
>
<view v-if="size === 'xs'" class="xs-goods-card ss-flex ss-col-stretch" :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>
</view>
<image
class="xs-img-box"
:src="sheep.$url.cdn(data.image || data.picUrl)"
mode="aspectFit"
></image>
<view
v-if="goodsFields.title?.show || goodsFields.name?.show || goodsFields.price?.show"
class="xs-goods-content ss-flex-col ss-row-around"
>
<view
v-if="goodsFields.title?.show || goodsFields.name?.show"
class="xs-goods-title ss-line-1"
:style="[{ color: titleColor, width: titleWidth ? titleWidth + 'rpx' : '' }]"
>
<image class="xs-img-box" :src="sheep.$url.cdn(data.image || data.picUrl)" mode="aspectFit"></image>
<view v-if="goodsFields.title?.show || goodsFields.name?.show || goodsFields.price?.show"
class="xs-goods-content ss-flex-col ss-row-around">
<view v-if="goodsFields.title?.show || goodsFields.name?.show" class="xs-goods-title ss-line-1"
:style="[{ color: titleColor, width: titleWidth ? titleWidth + 'rpx' : '' }]">
{{ data.title || data.name }}
</view>
<view
v-if="goodsFields.price?.show"
class="xs-goods-price font-OPPOSANS"
:style="[{ color: goodsFields.price.color }]"
>
<!-- 这里是新加的会员价和限时优惠 -->
<view class="iconBox" v-if="data.discountPrice || data.vipPrice || data.reward">
<view class="card" v-if="iconShow">{{iconShow}}</view>
<view class="card2" v-if="data.reward">{{data.reward.rewardActivity}}</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="iconShow=='限时优惠'">{{fen2yuan(data.discountPrice)}}</text>
<text v-else-if="iconShow==''">{{fen2yuan(data.vipPrice)}}</text>
<text v-else>{{ isArray(data.price) ? fen2yuan(data.price[0]) : fen2yuan(data.price) }}</text>
</view>
</view>
</view>
@ -43,30 +34,26 @@
<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="sm-img-box"
:src="sheep.$url.cdn(data.image || data.picUrl)"
mode="aspectFill"
></image>
<image class="sm-img-box" :src="sheep.$url.cdn(data.image || data.picUrl)" mode="aspectFill"></image>
<view
v-if="goodsFields.title?.show || goodsFields.name?.show || goodsFields.price?.show"
class="sm-goods-content"
:style="[{ color: titleColor, width: titleWidth ? titleWidth + 'rpx' : '' }]"
>
<view
v-if="goodsFields.title?.show || goodsFields.name?.show"
class="sm-goods-title ss-line-1 ss-m-b-16"
>
<view v-if="goodsFields.title?.show || goodsFields.name?.show || goodsFields.price?.show"
class="sm-goods-content" :style="[{ color: titleColor, width: titleWidth ? titleWidth + 'rpx' : '' }]">
<view v-if="goodsFields.title?.show || goodsFields.name?.show"
class="sm-goods-title ss-line-1 ss-m-b-16">
{{ data.title || data.name }}
</view>
<view
v-if="goodsFields.price?.show"
class="sm-goods-price font-OPPOSANS"
:style="[{ color: goodsFields.price.color }]"
>
<!-- 这里是新加的会员价和限时优惠 -->
<view class="iconBox" v-if="data.discountPrice || data.vipPrice || data.reward">
<view class="card" v-if="iconShow">{{iconShow}}</view>
<view class="card2" v-if="data.reward">{{data.reward.rewardActivity}}</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="iconShow=='限时优惠'">{{fen2yuan(data.discountPrice)}}</text>
<text v-else-if="iconShow==''">{{fen2yuan(data.vipPrice)}}</text>
<text v-else>{{ isArray(data.price) ? fen2yuan(data.price[0]) : fen2yuan(data.price) }}</text>
</view>
</view>
</view>
@ -76,58 +63,43 @@
<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="md-img-box"
:src="sheep.$url.cdn(data.image || data.picUrl)"
mode="widthFix"
></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 || goodsFields.name?.show"
class="md-goods-title ss-line-1"
:style="[{ color: titleColor, width: titleWidth ? titleWidth + 'rpx' : '' }]"
>
<image class="md-img-box" :src="sheep.$url.cdn(data.image || data.picUrl)" mode="widthFix"></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 || goodsFields.name?.show" class="md-goods-title ss-line-1"
:style="[{ color: titleColor, width: titleWidth ? titleWidth + 'rpx' : '' }]">
{{ data.title || data.name }}
</view>
<view
v-if="goodsFields.subtitle?.show || goodsFields.introduction?.show"
<view v-if="goodsFields.subtitle?.show || goodsFields.introduction?.show"
class="md-goods-subtitle ss-m-t-16 ss-line-1"
:style="[{ color: subTitleColor, background: subTitleBackground }]"
>
:style="[{ color: subTitleColor, background: subTitleBackground }]">
{{ data.subtitle || data.introduction }}
</view>
<slot name="activity">
<view v-if="data.promos?.length" class="tag-box ss-flex-wrap ss-flex ss-col-center">
<view
class="activity-tag ss-m-r-10 ss-m-t-16"
v-for="item in data.promos"
:key="item.id"
>
<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="iconBox" v-if="data.discountPrice || data.vipPrice || data.reward">
<view class="card" v-if="iconShow">{{iconShow}}</view>
<view class="card2" v-if="data.reward">{{data.reward.rewardActivity}}</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 }]"
>
<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="iconShow=='限时优惠'">{{fen2yuan(data.discountPrice)}}</text>
<text v-else-if="iconShow==''">{{fen2yuan(data.vipPrice)}}</text>
<text v-else>{{ isArray(data.price) ? fen2yuan(data.price[0]) : fen2yuan(data.price) }}</text>
</view>
<view
v-if="
<view v-if="
(goodsFields.original_price?.show || goodsFields.marketPrice?.show) &&
(data.original_price > 0 || data.marketPrice > 0)
"
class="goods-origin-price ss-m-t-16 font-OPPOSANS ss-flex"
:style="[{ color: originPriceColor }]"
>
" class="goods-origin-price ss-m-t-16 font-OPPOSANS ss-flex" :style="[{ color: originPriceColor }]">
<text class="price-unit ss-font-20">{{ priceUnit }}</text>
<view class="ss-m-l-8">{{ fen2yuan(data.marketPrice) }}</view>
</view>
@ -146,12 +118,7 @@
</view>
<!-- lg卡片横向型一行放一个图片左内容右边 -->
<view
v-if="size === 'lg'"
class="lg-goods-card ss-flex ss-col-stretch"
:style="[elStyles]"
@tap="onClick"
>
<view v-if="size === 'lg'" class="lg-goods-card ss-flex ss-col-stretch" :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>
</view>
@ -159,25 +126,16 @@
<view v-if="grouponTag" class="groupon-tag ss-flex ss-row-center">
<view class="tag-icon">拼团</view>
</view>
<image
class="lg-img-box"
:src="sheep.$url.cdn(data.image || data.picUrl)"
mode="aspectFill"
></image>
<image 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
v-if="goodsFields.title?.show || goodsFields.name?.show"
class="lg-goods-title ss-line-2"
:style="[{ color: titleColor }]"
>
<view v-if="goodsFields.title?.show || goodsFields.name?.show" class="lg-goods-title ss-line-2"
:style="[{ color: titleColor }]">
{{ data.title || data.name }}
</view>
<view
v-if="goodsFields.subtitle?.show || goodsFields.introduction?.show"
<view v-if="goodsFields.subtitle?.show || goodsFields.introduction?.show"
class="lg-goods-subtitle ss-m-t-10 ss-line-1"
:style="[{ color: subTitleColor, background: subTitleBackground }]"
>
:style="[{ color: subTitleColor, background: subTitleBackground }]">
{{ data.subtitle || data.introduction }}
</view>
</view>
@ -189,25 +147,27 @@
</view>
</view>
</slot>
<!-- 这里是新加的会员价和限时优惠 -->
<view class="iconBox" v-if="data.discountPrice || data.vipPrice || data.reward">
<view class="card" v-if="iconShow">{{iconShow}}</view>
<view class="card2" v-if="data.reward">{{data.reward.rewardActivity}}</view>
</view>
<!-- 这里是新加的会员价和限时优惠结束 -->
<view class="ss-flex ss-col-bottom ss-m-t-10">
<view
v-if="goodsFields.price?.show"
<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 }]"
>
:style="[{ color: goodsFields.price.color }]">
<text class="ss-font-24">{{ priceUnit }}</text>
{{ isArray(data.price) ? fen2yuan(data.price[0]) : fen2yuan(data.price) }}
</view>
<view
v-if="
<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"
:style="[{ color: originPriceColor }]"
>
" class="goods-origin-price ss-flex ss-col-bottom font-OPPOSANS" :style="[{ color: originPriceColor }]">
<text class="price-unit ss-font-20">{{ priceUnit }}</text>
<view class="ss-m-l-8">{{ fen2yuan(data.marketPrice) }}</view>
<text v-if="iconShow=='限时优惠'">{{fen2yuan(data.discountPrice)}}</text>
<text v-else-if="iconShow==''">{{fen2yuan(data.vipPrice)}}</text>
<text v-else>{{ isArray(data.price) ? fen2yuan(data.price[0]) : fen2yuan(data.price) }}</text>
</view>
</view>
<view class="ss-m-t-8 ss-flex ss-col-center ss-flex-wrap">
@ -227,54 +187,45 @@
<image class="tag-icon" :src="sheep.$url.cdn(tagStyle.src || tagStyle.imgUrl)"></image>
</view>
<image
class="sl-img-box"
:src="sheep.$url.cdn(data.image || data.picUrl)"
mode="aspectFill"
></image>
<image class="sl-img-box" :src="sheep.$url.cdn(data.image || data.picUrl)" mode="aspectFill"></image>
<view class="sl-goods-content">
<view>
<view
v-if="goodsFields.title?.show || goodsFields.name?.show"
class="sl-goods-title ss-line-1"
:style="[{ color: titleColor }]"
>
<view v-if="goodsFields.title?.show || goodsFields.name?.show" class="sl-goods-title ss-line-1"
:style="[{ color: titleColor }]">
{{ data.title || data.name }}
</view>
<view
v-if="goodsFields.subtitle?.show || goodsFields.introduction?.show"
<view v-if="goodsFields.subtitle?.show || goodsFields.introduction?.show"
class="sl-goods-subtitle ss-m-t-16"
:style="[{ color: subTitleColor, background: subTitleBackground }]"
>
:style="[{ color: subTitleColor, background: subTitleBackground }]">
{{ data.subtitle || data.introduction }}
</view>
</view>
<view>
<slot name="activity">
<view v-if="data.promos?.length" class="tag-box ss-flex ss-col-center ss-flex-wrap">
<view
class="activity-tag ss-m-r-10 ss-m-t-16"
v-for="item in data.promos"
:key="item.id"
>
<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="iconBox" v-if="data.discountPrice || data.vipPrice || data.reward">
<view class="card" v-if="iconShow">{{iconShow}}</view>
<view class="card2" v-if="data.reward">{{data.reward.rewardActivity}}</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="iconShow=='限时优惠'">{{fen2yuan(data.discountPrice)}}</text>
<text v-else-if="iconShow==''">{{fen2yuan(data.vipPrice)}}</text>
<text v-else>{{ isArray(data.price) ? fen2yuan(data.price[0]) : fen2yuan(data.price) }}</text>
</view>
<view
v-if="
<view v-if="
(goodsFields.original_price?.show || goodsFields.marketPrice?.show) &&
(data.original_price > 0 || data.marketPrice > 0)
"
class="goods-origin-price ss-m-t-16 font-OPPOSANS ss-flex"
:style="[{ color: originPriceColor }]"
>
" class="goods-origin-price ss-m-t-16 font-OPPOSANS ss-flex" :style="[{ color: originPriceColor }]">
<text class="price-unit ss-font-20">{{ priceUnit }}</text>
<view class="ss-m-l-8">{{ fen2yuan(data.marketPrice) }}</view>
</view>
@ -285,9 +236,9 @@
</view>
</view>
<slot name="cart"
><view class="buy-box ss-flex ss-col-center ss-row-center">去购买</view></slot
>
<slot name="cart">
<view class="buy-box ss-flex ss-col-center ss-row-center">去购买</view>
</slot>
</view>
</view>
</template>
@ -321,13 +272,26 @@
* @event {Function()} click - 点击卡片
*
*/
import { computed, reactive, getCurrentInstance, onMounted, nextTick } from 'vue';
import {
computed,
reactive,
getCurrentInstance,
onMounted,
nextTick,
ref
} from 'vue';
import sheep from '@/sheep';
import { fen2yuan, formatSales } from '@/sheep/hooks/useGoods';
import { formatStock } from '@/sheep/hooks/useGoods';
import {
fen2yuan,
formatSales
} from '@/sheep/hooks/useGoods';
import {
formatStock
} from '@/sheep/hooks/useGoods';
import goodsCollectVue from '@/pages/user/goods-collect.vue';
import { isArray } from 'lodash-es';
import {
isArray
} from 'lodash-es';
//
const state = reactive({});
@ -338,17 +302,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,7 +393,25 @@
default: false,
},
});
//
const iconShow = handle()
function handle() {
if (props.data.discountPrice === null && props.data.vipPrice === null) {
// null
return '';
} else if (props.data.discountPrice === null) {
// discountPrice null vipPrice
return '会员价';
} else if (props.data.vipPrice === null) {
// vipPrice null discountPrice
return '限时优惠';
} else if (props.data.discountPrice < props.data.vipPrice) {
return '限时优惠';
} else if (props.data.discountPrice > props.data.vipPrice) {
return '会员价';
}
}
//
const elStyles = computed(() => {
return {
@ -449,12 +443,18 @@
};
//
const { proxy } = getCurrentInstance();
const {
proxy
} = getCurrentInstance();
const elId = `sheep_${Math.ceil(Math.random() * 10e5).toString(36)}`;
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];
@ -482,11 +482,13 @@
left: 0;
top: 0;
z-index: 2;
.tag-icon {
width: 72rpx;
height: 44rpx;
}
}
.seckill-tag {
position: absolute;
left: 0;
@ -501,6 +503,7 @@
color: #ffffff;
line-height: 32rpx;
}
.groupon-tag {
position: absolute;
left: 0;
@ -515,14 +518,17 @@
color: #ffffff;
line-height: 32rpx;
}
.goods-img {
width: 100%;
height: 100%;
background-color: #f5f5f5;
}
.price-unit {
margin-right: -4px;
}
.sales-text {
display: table;
font-size: 24rpx;
@ -586,10 +592,12 @@
width: 100%;
height: 208rpx;
}
.sm-goods-content {
padding: 20rpx 16rpx;
box-sizing: border-box;
}
.sm-goods-title {
font-size: 26rpx;
color: #333;
@ -619,6 +627,7 @@
color: #333;
width: 100%;
}
.md-goods-subtitle {
font-size: 24rpx;
font-weight: 400;
@ -669,6 +678,7 @@
// line-height: 36rpx;
// width: 410rpx;
}
.lg-goods-subtitle {
font-size: 24rpx;
font-weight: 400;
@ -695,6 +705,7 @@
font-size: 24rpx;
color: #ffffff;
}
.tag-box {
width: 100%;
}
@ -708,10 +719,12 @@
z-index: 1;
width: 100%;
background-color: $white;
.sl-goods-content {
padding: 20rpx 20rpx;
box-sizing: border-box;
}
.sl-img-box {
width: 100%;
height: 360rpx;
@ -722,6 +735,7 @@
color: #333;
font-weight: 500;
}
.sl-goods-subtitle {
font-size: 24rpx;
font-weight: 400;
@ -748,4 +762,31 @@
color: #ffffff;
}
}
.card {
width: fit-content;
height: fit-content;
padding: 2rpx 10rpx;
background-color: red;
color: #ffffff;
font-size: 24rpx;
}
.card2 {
width: fit-content;
height: fit-content;
padding: 2rpx 10rpx;
background-color: rgb(255, 242, 241);
color: #ff2621;
font-size: 24rpx;
margin-left: 5rpx;
}
.iconBox {
width: 100%;
height: fit-content;
margin-top: 10rpx;
display: flex;
justify-content: flex-start;
}
</style>

View File

@ -13,6 +13,10 @@
<view class="ss-flex">
<view class="price-text">
{{ fen2yuan( state.selectedSku.price || goodsInfo.price) }}
<text v-if="state.selectedSku.type == 6"><text class="iconBox"></text><text
class="origin-price-text">{{fen2yuan(state.selectedSku.oldPrice)}}</text></text>
<text v-if="state.selectedSku.type == 4"><text class="iconBox"></text><text
class="origin-price-text">{{fen2yuan(state.selectedSku.oldPrice)}}</text></text>
</view>
</view>
<view class="stock-text ss-m-l-20">
@ -60,9 +64,17 @@
</template>
<script setup>
import { computed, reactive, watch } from 'vue';
import {
computed,
reactive,
watch
} from 'vue';
import sheep from '@/sheep';
import { formatStock, convertProductPropertyList, fen2yuan } from '@/sheep/hooks/useGoods';
import {
formatStock,
convertProductPropertyList,
fen2yuan
} from '@/sheep/hooks/useGoods';
const emits = defineEmits(['change', 'addCart', 'buy', 'close']);
const props = defineProps({
@ -82,7 +94,6 @@
});
const propertyList = convertProductPropertyList(props.goodsInfo.skus);
// SKU
const skuList = computed(() => {
let skuPrices = props.goodsInfo.skus;
@ -205,7 +216,8 @@
// property id SKU
for (let valueIndex in propertyList[propertyIndex]['values']) {
propertyList[propertyIndex]['values'][valueIndex]['disabled'] =
noChooseValueIds.indexOf(propertyList[propertyIndex]['values'][valueIndex]['id']) < 0; // true or false
noChooseValueIds.indexOf(propertyList[propertyIndex]['values'][valueIndex]['id']) <
0; // true or false
}
}
}
@ -403,4 +415,26 @@
}
}
}
.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>

View File

@ -1,7 +1,11 @@
import { ref } from 'vue';
import {
ref
} from 'vue';
import dayjs from 'dayjs';
import $url from '@/sheep/url';
import { formatDate } from '@/sheep/util';
import {
formatDate
} from '@/sheep/util';
/**
* 格式化销量
@ -80,7 +84,10 @@ export function formatGoodsSwiper(urlList) {
const isVideo = VIDEO_SUFFIX_LIST.some(suffix => url.includes(suffix));
const type = isVideo ? 'video' : 'image'
const src = $url.cdn(url);
return { type, src }
return {
type,
src
}
}) || [];
}
@ -94,9 +101,9 @@ export function formatOrderColor(order) {
if (order.status === 0) {
return 'info-color';
}
if (order.status === 10
|| order.status === 20
|| (order.status === 30 && !order.commentStatus)) {
if (order.status === 10 ||
order.status === 20 ||
(order.status === 30 && !order.commentStatus)) {
return 'warning-color';
}
if (order.status === 30 && order.commentStatus) {
@ -387,3 +394,92 @@ export function formatRewardActivityRule(activity, rule) {
}
return '';
}
// 新增将时间搓转换为开始时间-结束时间的格式
export function formatDateRange(startTimestamp, endTimestamp) {
// 定义一个辅助函数来格式化时间戳为 YYYY.MM.DD 格式
const formatDate = (timestamp) => {
const date = new Date(timestamp);
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0'); // 月份从0开始所以需要+1
const day = String(date.getDate()).padStart(2, '0');
return `${year}.${month}.${day}`;
};
// 格式化开始和结束时间
const start = formatDate(startTimestamp);
const end = formatDate(endTimestamp);
// 返回格式化的日期范围
return `${start}-${end}`;
}
//处理活动信息
export function handList(orders) {
const typeMap = {
'1': '秒杀活动',
'2': '砍价活动',
'3': '拼团活动',
'4': '限时折扣',
'5': '满减送',
'6': '会员折扣',
'7': '优惠券',
'8': '积分'
};
// 给每个订单对象添加 typeName 属性
let updatedOrders = orders.map(order => {
return {
...order, // 展开现有的订单对象属性
typeName: typeMap[order.type] // 添加 typeName 属性
};
});
return updatedOrders
};
//根据skuid来修改价格并添加时间
export function handListPrice(array,array2) {
// 将 array2 转换为一个以 skuId 为键的对象,以便于快速查找
const array2Map = array2.reduce((acc, item) => {
acc[item.skuId] = { price: item.price, type: item.type,endTime:item.endTime };
return acc;
}, {});
// 遍历 array 数组并更新 price 和 type
array.forEach(item => {
if (array2Map[item.id]) {
item.oldPrice = item.price
// 如果在 array2Map 中找到了对应的 skuId即 id
item.price = array2Map[item.id].price;
item.type = array2Map[item.id].type;
item.endTime = array2Map[item.id].endTime;
}
});
// 返回更新后的 array
return array;
};
//处理活动数据
export function handActitList(rules) {
const rules2 = {
reduc: rules.map(item => ({
discountPrice: item.discountPrice,
limit: item.limit,
bull: true // 默认为 true
})),
cou: rules.map(item => ({
discountPrice: item.discountPrice,
value: item.couponCounts.reduce((acc, count) => acc + count, 0), // 计算 couponCounts 中各项之和
bull: item.givePoint // 对应 givePoint
})),
ship: rules.map(item => ({
discountPrice: item.discountPrice,
bull: item.freeDelivery // 对应 freeDelivery
})),
scor: rules.map(item => ({
discountPrice: item.discountPrice,
value: item.point, // 直接使用 point
bull: item.givePoint // 对应 givePoint
}))
};
return rules2
};

BIN
static/images/dis.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB