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

410 lines
11 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<view class="pages-cart">
<u-navbar
leftIcon="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>