You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

659 lines
16 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<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>