Fix(购物车):[#1016]商品购买限制数量
This commit is contained in:
@@ -15,8 +15,10 @@ import {
|
|||||||
WX_LIVE_APPID
|
WX_LIVE_APPID
|
||||||
} from "@/config";
|
} from "@/config";
|
||||||
import uView from "uview-ui";
|
import uView from "uview-ui";
|
||||||
|
import GooSkeleton from '@/components/GooSkeleton/index.vue'
|
||||||
|
|
||||||
Vue.use(uView);
|
Vue.use(uView)
|
||||||
|
Vue.component('GooSkeleton', GooSkeleton)
|
||||||
Vue.mixin(mixin)
|
Vue.mixin(mixin)
|
||||||
|
|
||||||
// 注册全局组件
|
// 注册全局组件
|
||||||
|
|||||||
+201
-117
@@ -1,95 +1,166 @@
|
|||||||
<template>
|
<template>
|
||||||
<view class="pages-cart" v-if="ready">
|
<view class="pages-cart">
|
||||||
<u-navbar leftIcon="trash" title="购物车" fixed @leftClick="remove"/>
|
<u-navbar
|
||||||
|
leftIcon="trash"
|
||||||
<view class="tc" style="margin-top: 300rpx" v-if="list.length===0">
|
title="购物车"
|
||||||
<image style="width: 420rpx;height: 418rpx" :src="$VUE_APP_RESOURCES_URL+'/20240106211138206789.png'" mode="scaleToFill"/>
|
fixed
|
||||||
</view>
|
@leftClick="remove"
|
||||||
|
/>
|
||||||
<view class="group-item" v-for="(item,index) in list" :key="index">
|
<view v-if="isLoad">
|
||||||
|
<view
|
||||||
<view class="flex jc-between">
|
v-if="list.length === 0"
|
||||||
<view class="flex ai-center">
|
class="tc"
|
||||||
<CheckboxIcon style="margin-right: 24rpx;" :default-state="item['state']" :mark="[index]" @change="onChange"/>
|
style="margin-top: 300rpx"
|
||||||
<image class="store-cover" :src="item['merAvatar']"
|
>
|
||||||
mode="scaleToFill"/>
|
<image
|
||||||
<view style="color:#333333;font-size: 30rpx">{{ item['merName'] }}</view>
|
:src="$VUE_APP_RESOURCES_URL + '/20240106211138206789.png'"
|
||||||
</view>
|
style="width: 420rpx;height: 418rpx"
|
||||||
<view class="flex ai-center" style="color:#E92727;font-size: 24rpx" @click="navToStore(item['hotelId'])">
|
mode="scaleToFill"
|
||||||
进店逛逛
|
/>
|
||||||
<image style="width: 24rpx;height: 24rpx" :src="$VUE_APP_RESOURCES_URL+'/20240109234706982937.png'" mode="scaleToFill"/>
|
|
||||||
</view>
|
|
||||||
</view>
|
</view>
|
||||||
|
<view
|
||||||
<view class="goods-box">
|
v-for="(item, index) in list"
|
||||||
<view class="goods flex ai-center" v-for="(goods,gIndex) in item['carts']" :key="gIndex">
|
:key="index"
|
||||||
<CheckboxIcon style="margin-right: 24rpx;" :default-state="goods['state']" :mark="[index,gIndex]"
|
class="group-item"
|
||||||
@change="onChange"/>
|
>
|
||||||
<image class="goods-cover flex-0" :src="goods['productInfo']['attrInfo']['image']" mode="scaleToFill"
|
<view class="flex jc-between">
|
||||||
@click="navToGoods(goods['productId'])"
|
<view class="flex ai-center">
|
||||||
v-if="goods['productInfo']['attrInfo']['image']"/>
|
<CheckboxIcon
|
||||||
<image class="goods-cover flex-0" :src="goods['productInfo']['image']" mode="scaleToFill"
|
:default-state="item['state']"
|
||||||
@click="navToGoods(goods['productId'])" v-else/>
|
:mark="[index]"
|
||||||
|
style="margin-right: 24rpx;"
|
||||||
<view style="width: 100%">
|
@change="onChange"
|
||||||
<view class="one-t" @click="navToGoods(goods['productId'])">{{ goods['productInfo']['storeName'] }}</view>
|
/>
|
||||||
<view class="sku ai-center" @click="navToGoods(goods['productId'])">
|
<image
|
||||||
规格:{{ goods['productInfo']['attrInfo']['sku'] }}
|
:src="item['merAvatar']"
|
||||||
</view>
|
class="store-cover"
|
||||||
<view class="flex jc-between ai-center" style="width: 100%;margin-top: 26rpx;">
|
mode="scaleToFill"
|
||||||
<view style="color:#E92727;font-size: 32rpx;" @click="navToGoods(goods['productId'])">
|
/>
|
||||||
<text class="bold" style="font-size: 24rpx">¥</text>
|
<view style="color:#333333;font-size: 30rpx">{{ item['merName'] }}</view>
|
||||||
{{ goods['truePrice'] }}
|
</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>
|
||||||
<u-number-box class="num-step" v-model="goods['cartNum']" :name="goods['id']"
|
|
||||||
:max="goods['productInfo']['attrInfo']['stock']" integer disabledInput
|
|
||||||
iconStyle="color: #fff" @change="changeNum">
|
|
||||||
<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">{{ goods['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>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
<view class="footer-fixed flex jc-between ai-center">
|
||||||
|
<view style="margin-left: 32rpx;">
|
||||||
|
<CheckboxIcon
|
||||||
<view class="footer-fixed flex jc-between ai-center">
|
style="margin-right: 24rpx;"
|
||||||
<view style="margin-left: 32rpx;">
|
:default-state="isAll"
|
||||||
<CheckboxIcon style="margin-right: 24rpx;" :default-state="isAll" :mark="[-1]" @change="onChange"/>
|
:mark="[-1]"
|
||||||
<text style="color:#666666;font-size: 32rpx">全选({{ selectCount }})</text>
|
@change="onChange"
|
||||||
</view>
|
/>
|
||||||
<view class="flex ai-center">
|
<text style="color:#666666;font-size: 32rpx">全选({{ selectCount }})</text>
|
||||||
<view style="margin-right: 20rpx;color:#666666;font-size: 32rpx">合计:
|
</view>
|
||||||
<text class="bold" style="color:#E92727">¥{{ total }}</text>
|
<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 class="btn-submit bold flex jc-center ai-center" @click="submit">结算</view>
|
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
<goo-skeleton
|
||||||
|
v-else
|
||||||
|
:show-avatar="false"
|
||||||
|
/>
|
||||||
</view>
|
</view>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import {changeCartNum, getCartGroup, postCartDel} from "@/api/store";
|
import {changeCartNum, getCartGroup, postCartDel} from '@/api/store'
|
||||||
import CheckboxIcon from "@/components/CheckboxIcon.vue";
|
import CheckboxIcon from '@/components/CheckboxIcon.vue'
|
||||||
import {VUE_APP_RESOURCES_URL} from '../config/index'
|
|
||||||
export default {
|
export default {
|
||||||
components: {CheckboxIcon},
|
components: {
|
||||||
|
CheckboxIcon
|
||||||
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
ready: false,
|
isLoad: false,
|
||||||
webUrl: VUE_APP_RESOURCES_URL,
|
|
||||||
list: [],
|
list: [],
|
||||||
isAll: false
|
isAll: false
|
||||||
}
|
}
|
||||||
@@ -98,8 +169,8 @@ export default {
|
|||||||
total() {
|
total() {
|
||||||
let price = 0
|
let price = 0
|
||||||
this.list.forEach(item => {
|
this.list.forEach(item => {
|
||||||
item['carts'].forEach(goods => {
|
item['carts'].forEach(good => {
|
||||||
if (goods.state) price += Math.round(goods['cartNum'] * goods['truePrice'] * 100) / 100
|
if (good.state) price += Math.round(good['cartNum'] * good['truePrice'] * 100) / 100
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
return Math.round(price * 100) / 100
|
return Math.round(price * 100) / 100
|
||||||
@@ -107,38 +178,42 @@ export default {
|
|||||||
selectCount() {
|
selectCount() {
|
||||||
let count = 0
|
let count = 0
|
||||||
this.list.forEach(item => {
|
this.list.forEach(item => {
|
||||||
item['carts'].forEach(goods => {
|
item['carts'].forEach(good => {
|
||||||
if (goods.state) count++
|
if (good.state) count++
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
return count
|
return count
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
created() {
|
||||||
|
this.getCart()
|
||||||
|
},
|
||||||
onShow() {
|
onShow() {
|
||||||
|
if (!this.isLoad) {
|
||||||
|
return
|
||||||
|
}
|
||||||
this.getCart()
|
this.getCart()
|
||||||
this.ready = true
|
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
async getCart() {
|
async getCart() {
|
||||||
const res = await getCartGroup()
|
const res = await getCartGroup()
|
||||||
if (res.success) {
|
if (res.success) {
|
||||||
|
this.isLoad = true
|
||||||
this.list = res.data['valid']
|
this.list = res.data['valid']
|
||||||
this.handleAll(false)
|
this.handleAll(false)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
handleAll(state) {
|
handleAll(state) {
|
||||||
this.isAll = state
|
this.isAll = state
|
||||||
this.list = this.list.map(item => {
|
this.list = this.list.map(item => {
|
||||||
item.state = state
|
item.state = state
|
||||||
item.carts = item.carts.map(goods => {
|
item.carts = item.carts.map(good => {
|
||||||
goods.state = state
|
good.state = state
|
||||||
return goods
|
return good
|
||||||
})
|
})
|
||||||
return item
|
return item
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
navToStore(id) {
|
navToStore(id) {
|
||||||
if (id === 0) {
|
if (id === 0) {
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
@@ -148,65 +223,70 @@ export default {
|
|||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
uni.navigateTo({
|
uni.navigateTo({
|
||||||
url: '/pagesInn/inn/innHome?id=' + id
|
url: '/pagesInn/inn/innHome?id=' + id
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
onChange(state, mark) {
|
onChange(state, mark) {
|
||||||
if (mark.length === 1) {
|
if (mark.length === 1) {
|
||||||
if (mark[0] === -1) {
|
if (mark[0] === -1) {
|
||||||
this.handleAll(state)
|
this.handleAll(state)
|
||||||
} else {
|
} else {
|
||||||
this.list[mark[0]]['state'] = state
|
this.list[mark[0]]['state'] = state
|
||||||
this.list[mark[0]]['carts'] = this.list[mark[0]]['carts'].map(goods => {
|
this.list[mark[0]]['carts'] = this.list[mark[0]]['carts'].map(good => {
|
||||||
goods.state = state
|
good.state = state
|
||||||
return goods
|
return good
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mark.length === 2) {
|
if (mark.length === 2) {
|
||||||
this.list[mark[0]]['carts'][mark[1]]['state'] = state
|
this.list[mark[0]]['carts'][mark[1]]['state'] = state
|
||||||
const length = this.list[mark[0]]['carts'].length
|
const length = this.list[mark[0]]['carts'].length
|
||||||
let count = 0
|
let count = 0
|
||||||
this.list[mark[0]]['carts'] = this.list[mark[0]]['carts'].map((goods, gIndex) => {
|
this.list[mark[0]]['carts'] = this.list[mark[0]]['carts'].map((good, gIndex) => {
|
||||||
if (gIndex === mark[1]) goods['state'] = state
|
if (gIndex === mark[1]) good['state'] = state
|
||||||
if (goods['state']) count++
|
if (good['state']) count++
|
||||||
return goods
|
return good
|
||||||
})
|
})
|
||||||
this.list[mark[0]]['state'] = count === length
|
this.list[mark[0]]['state'] = count === length
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
changeNumHandle(index, gIndex, good, e) {
|
||||||
changeNum(event) {
|
const { type } = e
|
||||||
changeCartNum(event.name, event.value)
|
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() {
|
handleIds() {
|
||||||
if (this.selectCount === 0) {
|
if (this.selectCount === 0) {
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: "请选择产品",
|
title: '请选择产品',
|
||||||
icon: "none",
|
icon: 'none',
|
||||||
duration: 2000
|
duration: 2000
|
||||||
})
|
})
|
||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
|
const ids = []
|
||||||
let ids = []
|
|
||||||
this.list.forEach(item => {
|
this.list.forEach(item => {
|
||||||
item['carts'].forEach(goods => {
|
item['carts'].forEach(good => {
|
||||||
if (goods['state']) ids.push(goods['id'])
|
if (good['state']) ids.push(good['id'])
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
return ids
|
return ids
|
||||||
},
|
},
|
||||||
|
|
||||||
remove() {
|
remove() {
|
||||||
const ids = this.handleIds()
|
const ids = this.handleIds()
|
||||||
if (ids.length === 0) return
|
if (ids.length === 0) return
|
||||||
|
|
||||||
uni.showModal({
|
uni.showModal({
|
||||||
title: '确认删除已选商品?',
|
title: '确认删除已选商品?',
|
||||||
content: '',
|
content: '',
|
||||||
@@ -215,20 +295,24 @@ export default {
|
|||||||
confirmText: '确认',
|
confirmText: '确认',
|
||||||
success: async (result) => {
|
success: async (result) => {
|
||||||
if (result.confirm) {
|
if (result.confirm) {
|
||||||
const res = await postCartDel(ids)
|
uni.showLoading()
|
||||||
if (res.success) await this.getCart()
|
postCartDel(ids).then(res => {
|
||||||
|
const { success } = res
|
||||||
|
if (success) {
|
||||||
|
this.getCart()
|
||||||
|
}
|
||||||
|
}).finally(() => {
|
||||||
|
uni.hideLoading()
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
submit() {
|
submit() {
|
||||||
const ids = this.handleIds()
|
const ids = this.handleIds()
|
||||||
if (ids.length === 0) return
|
if (ids.length === 0) return
|
||||||
|
|
||||||
const param = ids.join(',')
|
|
||||||
uni.navigateTo({
|
uni.navigateTo({
|
||||||
url: '/pages/order/OrderSubmission/index?id=' + param
|
url: '/pages/order/OrderSubmission/index?id=' + ids.join(',')
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -261,11 +345,11 @@ view {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.goods-box {
|
.good-box {
|
||||||
.goods {
|
.good {
|
||||||
margin-top: 24rpx;
|
margin-top: 24rpx;
|
||||||
|
|
||||||
.goods-cover {
|
.good-cover {
|
||||||
width: 160rpx;
|
width: 160rpx;
|
||||||
height: 160rpx;
|
height: 160rpx;
|
||||||
margin-right: 16rpx;
|
margin-right: 16rpx;
|
||||||
|
|||||||
@@ -275,6 +275,9 @@
|
|||||||
},
|
},
|
||||||
// 发出change事件
|
// 发出change事件
|
||||||
emitChange(value) {
|
emitChange(value) {
|
||||||
|
const {
|
||||||
|
type
|
||||||
|
} = this
|
||||||
// 如果开启了异步变更值,则不修改内部的值,需要用户手动在外部通过v-model变更
|
// 如果开启了异步变更值,则不修改内部的值,需要用户手动在外部通过v-model变更
|
||||||
if (!this.asyncChange) {
|
if (!this.asyncChange) {
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
@@ -284,6 +287,7 @@
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
this.$emit('change', {
|
this.$emit('change', {
|
||||||
|
type,
|
||||||
value,
|
value,
|
||||||
name: this.name,
|
name: this.name,
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user