Files
xdd-uniapp-new/pages/cart.vue
T

410 lines
11 KiB
Vue

<template>
<view class="pages-cart">
<u-navbar
:left-icon="selectCount > 0 ? 'trash' : ''"
title="购物车"
fixed
@leftClick="remove"
/>
<view v-if="isLoad">
<view
v-if="list.length === 0"
class="tc"
style="margin-top: 300rpx"
>
<image
:src="$VUE_APP_RESOURCES_URL + '/20240106211138206789.png'"
style="width: 420rpx;height: 418rpx"
mode="scaleToFill"
/>
</view>
<view
v-for="(item, index) in list"
:key="index"
class="group-item"
>
<view class="flex jc-between">
<view class="flex ai-center">
<CheckboxIcon
:default-state="item['state']"
:mark="[index]"
style="margin-right: 24rpx;"
@change="onChange"
/>
<image
:src="item['merAvatar']"
class="store-cover"
mode="scaleToFill"
/>
<view style="color:#333333;font-size: 30rpx">{{ item['merName'] }}</view>
</view>
<view
class="flex ai-center"
style="color:#E92727;font-size: 24rpx"
@click="navToStore(item['hotelId'])"
>
进店逛逛
<image
:src="$VUE_APP_RESOURCES_URL + '/20240109234706982937.png'"
style="width: 24rpx;height: 24rpx"
mode="scaleToFill"
/>
</view>
</view>
<view class="good-box">
<view
v-for="(good, gIndex) in item['carts']"
:key="gIndex"
class="good flex ai-center"
>
<CheckboxIcon
:default-state="good['state']"
:mark="[index, gIndex]"
style="margin-right: 24rpx;"
@change="onChange"
/>
<image
v-if="good['productInfo']['attrInfo']['image']"
:src="good['productInfo']['attrInfo']['image']"
class="good-cover flex-0"
mode="scaleToFill"
@click="navToGood(good['productId'])"
/>
<image
v-else
:src="good['productInfo']['image']"
mode="scaleToFill"
class="good-cover flex-0"
@click="navToGood(good['productId'])"
/>
<view style="width: 100%">
<view
class="one-t"
@click="navToGood(good['productId'])"
>{{ good['productInfo']['storeName'] }}</view>
<view
class="sku ai-center"
@click="navToGood(good['productId'])"
>
规格:{{ good['productInfo']['attrInfo']['sku'] }}
</view>
<view
class="flex jc-between ai-center"
style="width: 100%;margin-top: 26rpx;"
>
<view
style="color:#E92727;font-size: 32rpx;"
@click="navToGood(good['productId'])"
>
<text class="bold" style="font-size: 24rpx">¥</text>
{{ good['truePrice'] }}
</view>
<u-number-box
:value="good.cartNum"
:max="good['productInfo']['attrInfo']['stock']"
integer
disabledInput
iconStyle="color: #fff"
class="num-step"
@change="e => changeNumHandle(index, gIndex, good, e)"
>
<template v-slot:minus>
<view class="num-btn flex jc-center ai-center">
<u-icon name="minus" size="12" color="#FFFFFF"/>
</view>
</template>
<template v-slot:input>
<view class="num-input tc">{{ good['cartNum'] }}</view>
</template>
<template v-slot:plus>
<view class="num-btn flex jc-center ai-center">
<u-icon name="plus" size="12" color="#FFFFFF"/>
</view>
</template>
</u-number-box>
</view>
</view>
</view>
</view>
</view>
<view class="footer-fixed flex jc-between ai-center">
<view style="margin-left: 32rpx;">
<CheckboxIcon
style="margin-right: 24rpx;"
:default-state="isAll"
:mark="[-1]"
@change="onChange"
/>
<text style="color:#666666;font-size: 32rpx">全选({{ selectCount }})</text>
</view>
<view class="flex ai-center">
<view style="margin-right: 20rpx;color:#666666;font-size: 32rpx">合计:
<text class="bold" style="color:#E92727">¥{{ total }}</text>
</view>
<view class="btn-submit bold flex jc-center ai-center" @click="submit">结算</view>
</view>
</view>
</view>
<goo-skeleton
v-else
:show-avatar="false"
/>
</view>
</template>
<script>
import {changeCartNum, getCartGroup, postCartDel} from '@/api/store'
import CheckboxIcon from '@/components/CheckboxIcon.vue'
export default {
components: {
CheckboxIcon
},
data() {
return {
isLoad: false,
list: [],
isAll: false
}
},
computed: {
total() {
let price = 0
this.list.forEach(item => {
item['carts'].forEach(good => {
if (good.state) price += Math.round(good['cartNum'] * good['truePrice'] * 100) / 100
})
})
return Math.round(price * 100) / 100
},
selectCount() {
let count = 0
this.list.forEach(item => {
item['carts'].forEach(good => {
if (good.state) count++
})
})
return count
}
},
created() {
this.getCart()
},
onShow() {
if (!this.isLoad) {
return
}
this.getCart()
},
methods: {
async getCart() {
const res = await getCartGroup()
if (res.success) {
this.isLoad = true
this.list = res.data['valid']
this.handleAll(false)
}
},
handleAll(state) {
this.isAll = state
this.list = this.list.map(item => {
item.state = state
item.carts = item.carts.map(good => {
good.state = state
return good
})
return item
})
},
navToStore(id) {
if (id === 0) {
uni.showToast({
title: '店铺装修中~',
icon: 'none',
duration: 3000
})
return
}
uni.navigateTo({
url: '/pagesInn/inn/innHome?id=' + id
})
},
onChange(state, mark) {
if (mark.length === 1) {
if (mark[0] === -1) {
this.handleAll(state)
} else {
this.list[mark[0]]['state'] = state
this.list[mark[0]]['carts'] = this.list[mark[0]]['carts'].map(good => {
good.state = state
return good
})
}
}
if (mark.length === 2) {
this.list[mark[0]]['carts'][mark[1]]['state'] = state
const length = this.list[mark[0]]['carts'].length
let count = 0
this.list[mark[0]]['carts'] = this.list[mark[0]]['carts'].map((good, gIndex) => {
if (gIndex === mark[1]) good['state'] = state
if (good['state']) count++
return good
})
this.list[mark[0]]['state'] = count === length
}
},
changeNumHandle(index, gIndex, good, e) {
const { type } = e
const value = good.cartNum + (type === 'plus' ? 1 : -1)
const id = good.id
uni.showLoading()
changeCartNum(id, value).then(res => {
const { success } = res
if (success) {
this.$set(this.list[index].carts[gIndex], 'cartNum', value)
}
}).catch(() => {
uni.hideLoading()
}).finally(() => {
uni.hideLoading()
})
},
handleIds() {
if (this.selectCount === 0) {
uni.showToast({
title: '请选择产品',
icon: 'none',
duration: 2000
})
return []
}
const ids = []
this.list.forEach(item => {
item['carts'].forEach(good => {
if (good['state']) ids.push(good['id'])
})
})
return ids
},
remove() {
const ids = this.handleIds()
if (ids.length === 0) return
uni.showModal({
title: '确认删除已选商品?',
content: '',
showCancel: true,
cancelText: '取消',
confirmText: '确认',
success: async (result) => {
if (result.confirm) {
uni.showLoading()
postCartDel(ids).then(res => {
const { success } = res
if (success) {
this.getCart()
}
}).finally(() => {
uni.hideLoading()
})
}
}
})
},
submit() {
const ids = this.handleIds()
if (ids.length === 0) return
uni.navigateTo({
url: '/pages/order/OrderSubmission/index?id=' + ids.join(',')
})
}
}
}
</script>
<style scoped lang="less">
view {
box-sizing: border-box;
}
.pages-cart {
min-height: 100vh;
padding-top: calc(var(--status-bar-height) + 54px);
padding-bottom: 100rpx;
}
.group-item {
width: 710rpx;
margin: 12rpx 20rpx;
padding: 8rpx 8rpx 32rpx 20rpx;
background: #FFFFFF;
border-radius: 12rpx;
.store-cover {
width: 48rpx;
height: 48rpx;
margin-right: 8rpx;
border-radius: 50%;
}
}
.good-box {
.good {
margin-top: 24rpx;
.good-cover {
width: 160rpx;
height: 160rpx;
margin-right: 16rpx;
border-radius: 8rpx;
}
.one-t {
width: 420rpx;
color: #333333;
font-size: 30rpx;
line-height: 42rpx;
font-weight: bold;
}
.sku {
display: inline-flex;
margin-top: 12rpx;
padding: 10rpx 20rpx;
border-radius: 22rpx;
background: #FDF1F3;
color: #999999;
font-size: 28rpx;
}
.num-btn {
width: 40rpx;
height: 40rpx;
background: rgba(236, 236, 238, 1);
border: 2px solid rgba(236, 236, 238, 1);
border-radius: 50%;
}
.num-input {
width: 64rpx;
color: #333333;
font-size: 30rpx;
}
}
}
.footer-fixed {
position: fixed;
left: 0;
bottom: 0;
width: 100vw;
height: 100rpx;
box-shadow: 0 6rpx 12rpx rgba(0, 0, 0, 0.16);
background: #FFFFFF;
.btn-submit {
width: 196rpx;
height: 100rpx;
background: #FD5749;
color: #FFFFFF;
font-size: 32rpx;
}
}
</style>