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

1 year ago
<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
}
1 year ago
this.$u.route({
url: '/package_sub/pages/Shop/Pay',
params: {
// ids: this.pickCart.map(i => i.id).toString()
}
})
}
},
computed: {
totalPrice() {
1 year ago
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))
1 year ago
// 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>