|
|
<template>
|
|
|
<view>
|
|
|
<navbar :use-search="false" title="购物车"></navbar>
|
|
|
|
|
|
<view class="wrap">
|
|
|
<view class="carts">
|
|
|
<u-swipe-action
|
|
|
v-for="(item, index) in carts"
|
|
|
:key="item.id"
|
|
|
:show="item.show"
|
|
|
:index="index"
|
|
|
style="margin: 20rpx;"
|
|
|
:options="options"
|
|
|
@click="destroyCart">
|
|
|
<view class="cart">
|
|
|
<view class="top">
|
|
|
<!-- <u-checkbox-->
|
|
|
<!-- class="cart__checkbox"-->
|
|
|
<!-- shape="circle"-->
|
|
|
<!-- :disabled="!(item.product_sku && item.product_sku.stock_num)"-->
|
|
|
<!-- :value="(pickCart.findIndex(i => i.id === item.id) !== -1) && (item.product_sku && item.product_sku.stock_num)"-->
|
|
|
<!-- @tap="-->
|
|
|
<!-- () => {-->
|
|
|
<!-- if (item.product_sku && item.product_sku.stock_num) {-->
|
|
|
<!-- if (pickCart.findIndex(i => i.id === item.id) === -1) {-->
|
|
|
<!-- pickCart.push(item)-->
|
|
|
<!-- } else {-->
|
|
|
<!-- pickCart.splice(pickCart.findIndex(i => i.id === item.id), 1)-->
|
|
|
<!-- }-->
|
|
|
<!-- }-->
|
|
|
<!-- }-->
|
|
|
<!-- "-->
|
|
|
<!-- ></u-checkbox>-->
|
|
|
<u-image
|
|
|
class="cart__img"
|
|
|
width="154rpx"
|
|
|
height="154rpx"
|
|
|
lazy-load
|
|
|
:src="
|
|
|
item.product && item.product.image
|
|
|
? item.product.image.url
|
|
|
: vuex_default_icon
|
|
|
"
|
|
|
></u-image>
|
|
|
<view class="cart__info">
|
|
|
<view class="cart__info--name">{{
|
|
|
item.product ? item.product.name : ""
|
|
|
}}</view>
|
|
|
<view class="cart__info--type" @tap.stop="getDetail(item)">
|
|
|
<text>
|
|
|
{{ item.product_sku ? item.product_sku.name : "" }}
|
|
|
</text>
|
|
|
<u-icon
|
|
|
name="arrow-down"
|
|
|
:size="22"
|
|
|
style="margin-left: 6rpx"
|
|
|
color="#333"
|
|
|
></u-icon>
|
|
|
</view>
|
|
|
<view class="cart__info--price">
|
|
|
<text>¥</text>
|
|
|
<text>{{
|
|
|
item.product_sku ? item.product_sku.price : ""
|
|
|
}}</text>
|
|
|
</view>
|
|
|
</view>
|
|
|
</view>
|
|
|
<view
|
|
|
class="bottom"
|
|
|
v-if="item.product_sku && item.product_sku.stock_num"
|
|
|
>
|
|
|
<u-number-box
|
|
|
v-model="item.num"
|
|
|
:size="22"
|
|
|
:input-width="54"
|
|
|
:input-height="44"
|
|
|
:min="1"
|
|
|
:max="item.product_sku ? item.product_sku.stock_num : 0"
|
|
|
@change.stop="saveCart(item)"
|
|
|
></u-number-box>
|
|
|
</view>
|
|
|
</view>
|
|
|
</u-swipe-action>
|
|
|
</view>
|
|
|
|
|
|
<view class="recommend">
|
|
|
<view class="recommend-title">
|
|
|
<view class="cir"></view>
|
|
|
<view class="cir"></view>
|
|
|
<view class="cir"></view>
|
|
|
<text>猜你喜欢</text>
|
|
|
<view class="cir"></view>
|
|
|
<view class="cir"></view>
|
|
|
<view class="cir"></view>
|
|
|
</view>
|
|
|
<view class="recommend-wrap">
|
|
|
<view
|
|
|
class="product-item"
|
|
|
v-for="item in recommendPro"
|
|
|
:key="item.id"
|
|
|
@tap="
|
|
|
$u.throttle(() => {
|
|
|
toDetail(item);
|
|
|
}, 500)
|
|
|
"
|
|
|
>
|
|
|
<view class="top">
|
|
|
<image
|
|
|
class="product-item__img"
|
|
|
:src="item.image ? item.image.url : ''"
|
|
|
mode="aspectFill"
|
|
|
></image>
|
|
|
</view>
|
|
|
<view class="bottom">
|
|
|
<view class="product-item__title">
|
|
|
{{ item.name }}
|
|
|
</view>
|
|
|
<view class="product-item__price">
|
|
|
<view>
|
|
|
<text>¥</text>
|
|
|
<text>{{ item.price }}</text>
|
|
|
</view>
|
|
|
</view>
|
|
|
</view>
|
|
|
</view>
|
|
|
</view>
|
|
|
</view>
|
|
|
|
|
|
<view class="bar" :style="'bottom:' + barOffsetBottom + 'px'">
|
|
|
<!-- <view class="check">-->
|
|
|
<!-- <u-checkbox-->
|
|
|
<!-- class="check__checkbox"-->
|
|
|
<!-- shape="circle"-->
|
|
|
<!-- :label-size="25"-->
|
|
|
<!-- :value="pickCart.length === carts.length && pickCart.length !== 0"-->
|
|
|
<!-- @tap="-->
|
|
|
<!-- () => {-->
|
|
|
<!-- if (pickCart.length === carts.length) {-->
|
|
|
<!-- pickCart = []-->
|
|
|
<!-- } else {-->
|
|
|
<!-- pickCart = carts-->
|
|
|
<!-- }-->
|
|
|
<!-- }-->
|
|
|
<!-- "-->
|
|
|
<!-- >全选</u-checkbox>-->
|
|
|
<!-- </view>-->
|
|
|
<view class="total">
|
|
|
<text>合计:</text>
|
|
|
<text>¥</text>
|
|
|
<text>{{
|
|
|
totalPrice
|
|
|
}}</text>
|
|
|
</view>
|
|
|
<u-button
|
|
|
ripple
|
|
|
shape="circle"
|
|
|
:hair-line="false"
|
|
|
:custom-style="{
|
|
|
color: '#fff',
|
|
|
background: 'linear-gradient(0deg, #ff2a00 0%, #f26011 100%)',
|
|
|
width: '154rpx',
|
|
|
height: '60rpx',
|
|
|
'line-height': '60rpx',
|
|
|
'margin-left': '14rpx',
|
|
|
}"
|
|
|
@click.stop="pay"
|
|
|
>付款</u-button
|
|
|
>
|
|
|
</view>
|
|
|
</view>
|
|
|
|
|
|
<!-- 类型选择 -->
|
|
|
<u-popup
|
|
|
v-model="showType"
|
|
|
mode="bottom"
|
|
|
border-radius="14"
|
|
|
safe-area-inset-bottom
|
|
|
>
|
|
|
<view class="content">
|
|
|
<scroll-view scroll-y="true" style="height: 800rpx">
|
|
|
<view class="product">
|
|
|
<view
|
|
|
class="product-item"
|
|
|
:class="{
|
|
|
'product-item-active': cartDetail.product_sku_id === item.id,
|
|
|
}"
|
|
|
v-for="item in productDetail.product_skus || []"
|
|
|
:key="item.id"
|
|
|
@click="
|
|
|
() => {
|
|
|
if (item.stock_num) {
|
|
|
cartDetail.product_sku_id = item.id;
|
|
|
}
|
|
|
}
|
|
|
"
|
|
|
>
|
|
|
<view class="top">
|
|
|
<image
|
|
|
class="product-item__img"
|
|
|
:src="item.image ? item.image.url : ''"
|
|
|
mode="aspectFill"
|
|
|
></image>
|
|
|
<image
|
|
|
class="product-item__soldout"
|
|
|
v-if="!item.stock_num"
|
|
|
src="~@/package_sub/static/Shop/yishouxing.png"
|
|
|
mode="aspectFit"
|
|
|
></image>
|
|
|
</view>
|
|
|
<view class="bottom">
|
|
|
<view class="product-item__title">
|
|
|
{{ item.name }}
|
|
|
</view>
|
|
|
<view class="product-item__price">
|
|
|
<view>
|
|
|
<text>¥</text>
|
|
|
<text>{{ item.price }}</text>
|
|
|
</view>
|
|
|
</view>
|
|
|
</view>
|
|
|
<u-icon
|
|
|
class="product-item-active__check"
|
|
|
name="checkmark-circle-fill"
|
|
|
color="red"
|
|
|
:size="40"
|
|
|
v-if="cartDetail.product_sku_id === item.id"
|
|
|
></u-icon>
|
|
|
</view>
|
|
|
</view>
|
|
|
</scroll-view>
|
|
|
<view class="confirm-btn">
|
|
|
<u-button
|
|
|
:hair-line="false"
|
|
|
:custom-style="{
|
|
|
'background-image':
|
|
|
'linear-gradient(-90deg, #e26165 0%, #c10d12 94%, #c10d12 100%)',
|
|
|
color: '#fff',
|
|
|
width: '80%',
|
|
|
'margin-top': '20rpx',
|
|
|
}"
|
|
|
@click="saveCart(cartDetail)"
|
|
|
>确定</u-button
|
|
|
>
|
|
|
</view>
|
|
|
</view>
|
|
|
</u-popup>
|
|
|
<u-toast ref="uToast" />
|
|
|
|
|
|
<tabbar class="tabbar"></tabbar>
|
|
|
</view>
|
|
|
</template>
|
|
|
|
|
|
<script>
|
|
|
import BigNumber from "@/libs/bignumber";
|
|
|
import tabbar from "@/package_sub/pages/Shop/Tabbar.vue";
|
|
|
import navbar from "@/package_sub/pages/Shop/Navbar.vue";
|
|
|
|
|
|
export default {
|
|
|
components: {
|
|
|
navbar,
|
|
|
tabbar,
|
|
|
},
|
|
|
data() {
|
|
|
return {
|
|
|
options: [
|
|
|
{
|
|
|
text: '删除',
|
|
|
style: {
|
|
|
backgroundColor: '#dd524d'
|
|
|
}
|
|
|
}
|
|
|
],
|
|
|
pickCart: [],
|
|
|
carts: [],
|
|
|
select: {
|
|
|
page: 1,
|
|
|
page_size: 999,
|
|
|
"show_relation[0]": "product.image",
|
|
|
"show_relation[1]": "productSku",
|
|
|
},
|
|
|
total: 0,
|
|
|
barOffsetBottom: 500,
|
|
|
recommendPro: [],
|
|
|
|
|
|
cartDetail: {},
|
|
|
productDetail: {},
|
|
|
showType: false,
|
|
|
};
|
|
|
},
|
|
|
methods: {
|
|
|
async getDetail(cart) {
|
|
|
this.cartDetail = cart;
|
|
|
try {
|
|
|
const res = await this.$u.api.productDetail({
|
|
|
id: cart.product_id,
|
|
|
});
|
|
|
this.productDetail = res.detail;
|
|
|
this.showType = true;
|
|
|
} catch (err) {
|
|
|
console.error(err);
|
|
|
}
|
|
|
},
|
|
|
async saveCart(data) {
|
|
|
try {
|
|
|
await this.$u.api.cartSave(data);
|
|
|
const res = await this.$u.api.cartShow({
|
|
|
id: data.id,
|
|
|
"show_relation[0]": "product.image",
|
|
|
"show_relation[1]": "productSku",
|
|
|
});
|
|
|
let index = this.carts.findIndex((i) => i.id === res.id);
|
|
|
if (index !== -1) {
|
|
|
this.carts.splice(index, 1, res);
|
|
|
}
|
|
|
this.showType = false;
|
|
|
} catch (err) {}
|
|
|
},
|
|
|
// 获取一个目标元素的高度
|
|
|
getElRect(elClass, dataVal) {
|
|
|
return new Promise((resolve, reject) => {
|
|
|
const query = uni.createSelectorQuery().in(this);
|
|
|
query
|
|
|
.select("." + elClass)
|
|
|
.fields(
|
|
|
{
|
|
|
size: true,
|
|
|
},
|
|
|
(res) => {
|
|
|
// 如果节点尚未生成,res值为null,循环调用执行
|
|
|
if (!res) {
|
|
|
setTimeout(() => {
|
|
|
this.getElRect(elClass);
|
|
|
}, 10);
|
|
|
return;
|
|
|
}
|
|
|
if (dataVal) {
|
|
|
this["dataVal"] = res.top;
|
|
|
}
|
|
|
|
|
|
resolve(res);
|
|
|
}
|
|
|
)
|
|
|
.exec();
|
|
|
});
|
|
|
},
|
|
|
async destroyCart(index, index1) {
|
|
|
this.$u.throttle(async () => {
|
|
|
if(index1 === 0) {
|
|
|
try {
|
|
|
await this.$u.api.cartDestroy({
|
|
|
id: this.carts[index].id
|
|
|
})
|
|
|
await this.getCarts()
|
|
|
} catch (err) {
|
|
|
console.error(err)
|
|
|
}
|
|
|
}
|
|
|
}, 1000)
|
|
|
},
|
|
|
async getCarts() {
|
|
|
try {
|
|
|
const res = await this.$u.api.cartList(this.select);
|
|
|
this.carts = res.data;
|
|
|
this.total = res.total;
|
|
|
} catch (err) {
|
|
|
console.error(err);
|
|
|
}
|
|
|
},
|
|
|
toDetail(item) {
|
|
|
this.$u.route({
|
|
|
url: "/package_sub/pages/Shop/ProductDetail",
|
|
|
params: {
|
|
|
id: item.id,
|
|
|
},
|
|
|
});
|
|
|
},
|
|
|
async getRecommendPro() {
|
|
|
try {
|
|
|
const res = await this.$u.api.productList({
|
|
|
page: 1,
|
|
|
page_size: 6,
|
|
|
sort_name: "sort",
|
|
|
});
|
|
|
this.recommendPro = res.list?.data;
|
|
|
} catch (err) {}
|
|
|
},
|
|
|
pay() {
|
|
|
if (this.carts.length <= 0) {
|
|
|
this.$refs.uToast.show({
|
|
|
title: "请选择下单商品",
|
|
|
type: "warning",
|
|
|
});
|
|
|
return
|
|
|
}
|
|
|
this.$u.route({
|
|
|
url: '/package_sub/pages/Shop/Pay',
|
|
|
params: {
|
|
|
// ids: this.pickCart.map(i => i.id).toString()
|
|
|
}
|
|
|
})
|
|
|
}
|
|
|
},
|
|
|
computed: {
|
|
|
totalPrice() {
|
|
|
return this.carts?.reduce((pre, cur) => pre.plus(new BigNumber(isNaN(Number(cur.product_sku?.price??0)) ? 0 : Number(cur.product_sku?.price??0)).times(cur.num??0)), new BigNumber(0))
|
|
|
// return this.pickCart?.reduce((pre, cur) => pre + (isNaN(Number(cur.product_sku?.price??0)) ? 0 : Number(cur.product_sku?.price??0)), 0)
|
|
|
}
|
|
|
},
|
|
|
mounted() {
|
|
|
this.getElRect("tabbar").then((res) => {
|
|
|
this.barOffsetBottom = res.height;
|
|
|
});
|
|
|
},
|
|
|
created() {
|
|
|
this.getRecommendPro();
|
|
|
this.getCarts(true);
|
|
|
},
|
|
|
};
|
|
|
</script>
|
|
|
|
|
|
<style lang="scss">
|
|
|
page {
|
|
|
background: #f5f5f5;
|
|
|
}
|
|
|
.recommend {
|
|
|
padding-bottom: 60rpx;
|
|
|
position: relative;
|
|
|
z-index: 2;
|
|
|
|
|
|
&-title {
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
justify-content: center;
|
|
|
color: red;
|
|
|
& > text {
|
|
|
padding: 0 6rpx;
|
|
|
}
|
|
|
.cir {
|
|
|
background: red;
|
|
|
border-radius: 100%;
|
|
|
margin: 0 4rpx;
|
|
|
}
|
|
|
.cir:first-child,
|
|
|
.cir:last-child,
|
|
|
.cir:nth-child(2),
|
|
|
.cir:nth-last-child(2) {
|
|
|
width: 5rpx;
|
|
|
height: 5rpx;
|
|
|
}
|
|
|
.cir:nth-child(3),
|
|
|
.cir:nth-last-child(3) {
|
|
|
width: 8rpx;
|
|
|
height: 8rpx;
|
|
|
transform: translateY(-4rpx);
|
|
|
}
|
|
|
}
|
|
|
&-wrap {
|
|
|
padding: 0 20rpx;
|
|
|
display: grid;
|
|
|
grid-template-columns: repeat(2, 1fr);
|
|
|
grid-gap: 20rpx 56rpx;
|
|
|
margin-top: 36rpx;
|
|
|
|
|
|
.product-item {
|
|
|
background: #fff;
|
|
|
padding: 12rpx;
|
|
|
|
|
|
.bottom {
|
|
|
padding-top: 16rpx;
|
|
|
}
|
|
|
&__img {
|
|
|
width: 100%;
|
|
|
height: 266rpx;
|
|
|
}
|
|
|
&__title {
|
|
|
font-size: 25rpx;
|
|
|
color: #333333;
|
|
|
overflow: hidden;
|
|
|
display: -webkit-box;
|
|
|
-webkit-line-clamp: 2;
|
|
|
-webkit-box-orient: vertical;
|
|
|
word-break: break-all;
|
|
|
}
|
|
|
&__price {
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
justify-content: space-between;
|
|
|
|
|
|
text {
|
|
|
color: red;
|
|
|
}
|
|
|
text:nth-child(1) {
|
|
|
font-size: 21rpx;
|
|
|
}
|
|
|
text:nth-child(2) {
|
|
|
font-size: 32rpx;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
.carts {
|
|
|
margin-top: 20rpx;
|
|
|
|
|
|
.cart {
|
|
|
background: #fff;
|
|
|
border-radius: 8rpx;
|
|
|
padding: 26rpx 22rpx 16rpx;
|
|
|
.top {
|
|
|
display: flex;
|
|
|
justify-content: space-between;
|
|
|
}
|
|
|
.bottom {
|
|
|
margin-top: 14rpx;
|
|
|
display: flex;
|
|
|
justify-content: flex-end;
|
|
|
}
|
|
|
|
|
|
&__checkbox {
|
|
|
align-self: center;
|
|
|
}
|
|
|
&__img {
|
|
|
border-radius: 6rpx;
|
|
|
}
|
|
|
&__info {
|
|
|
flex: 1;
|
|
|
margin-left: 28rpx;
|
|
|
&--name {
|
|
|
font-size: 24rpx;
|
|
|
color: #333333;
|
|
|
}
|
|
|
&--type {
|
|
|
margin-top: 14rpx;
|
|
|
font-size: 21rpx;
|
|
|
display: inline-block;
|
|
|
color: #666;
|
|
|
border-radius: 8rpx;
|
|
|
background-color: #f5f5f5;
|
|
|
padding: 14rpx 12rpx;
|
|
|
max-width: 320rpx;
|
|
|
overflow: hidden;
|
|
|
white-space: nowrap;
|
|
|
text-overflow: ellipsis;
|
|
|
}
|
|
|
&--price {
|
|
|
margin-top: 14rpx;
|
|
|
color: red;
|
|
|
font-size: 21rpx;
|
|
|
|
|
|
& > text:nth-child(2) {
|
|
|
font-size: 24rpx;
|
|
|
padding-left: 4rpx;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
.wrap {
|
|
|
position: relative;
|
|
|
}
|
|
|
.bar {
|
|
|
width: 100%;
|
|
|
background: #fff;
|
|
|
position: sticky;
|
|
|
bottom: 400rpx;
|
|
|
display: flex;
|
|
|
justify-content: space-between;
|
|
|
align-items: center;
|
|
|
z-index: 10;
|
|
|
padding: 20rpx;
|
|
|
filter: drop-shadow(0 -1rpx 1rpx #00000012);
|
|
|
|
|
|
.total {
|
|
|
margin-left: auto;
|
|
|
|
|
|
text {
|
|
|
font-size: 25rpx;
|
|
|
color: #ff0000;
|
|
|
}
|
|
|
& > text:nth-child(1) {
|
|
|
color: #333333;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
.product {
|
|
|
padding: 80rpx 20rpx;
|
|
|
display: grid;
|
|
|
grid-template-columns: repeat(2, 1fr);
|
|
|
grid-gap: 40rpx;
|
|
|
|
|
|
&-item {
|
|
|
background: #f5f5f5;
|
|
|
border: 1px solid transparent;
|
|
|
padding: 10rpx;
|
|
|
border-radius: 10rpx;
|
|
|
position: relative;
|
|
|
|
|
|
.bottom {
|
|
|
padding-top: 16rpx;
|
|
|
}
|
|
|
.top {
|
|
|
position: relative;
|
|
|
}
|
|
|
&__soldout {
|
|
|
height: 266rpx;
|
|
|
width: 100%;
|
|
|
padding: 40rpx;
|
|
|
box-sizing: border-box;
|
|
|
background: #ffffff99;
|
|
|
opacity: 0.86;
|
|
|
position: absolute;
|
|
|
top: 0;
|
|
|
left: 0;
|
|
|
right: 0;
|
|
|
bottom: 0;
|
|
|
}
|
|
|
&__img {
|
|
|
width: 100%;
|
|
|
height: 266rpx;
|
|
|
}
|
|
|
&__title {
|
|
|
font-size: 25rpx;
|
|
|
color: #333333;
|
|
|
overflow: hidden;
|
|
|
display: -webkit-box;
|
|
|
-webkit-line-clamp: 2;
|
|
|
-webkit-box-orient: vertical;
|
|
|
word-break: break-all;
|
|
|
}
|
|
|
&__price {
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
justify-content: space-between;
|
|
|
|
|
|
text {
|
|
|
color: red;
|
|
|
}
|
|
|
text:nth-child(1) {
|
|
|
font-size: 21rpx;
|
|
|
}
|
|
|
text:nth-child(2) {
|
|
|
font-size: 32rpx;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
&-active {
|
|
|
border-color: red;
|
|
|
|
|
|
&__check {
|
|
|
position: absolute;
|
|
|
top: 10rpx;
|
|
|
right: 10rpx;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
</style>
|