123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397 |
- <template>
- <view class="cart">
- <tui-skeleton v-if="isRequest" :loadingType="3" :isLoading="true"></tui-skeleton>
- <!-- 购物车列表为空 -->
- <template v-if="shopList.length === 0 && expiredProducts.length === 0">
- <tui-no-data :imgUrl="staticUrl + 'icon-empty-cart.png'" :imgHeight="230" :imgWidth="290">
- <view class="empty-tip">购物车空空的,快去逛逛吧~</view>
- </tui-no-data>
- </template>
- <template v-else>
- <!-- 顶部 -->
- <template v-if="!isDeleted">
- <view class="sticky-top">
- <view class="goods-total">
- <view class="total">共{{ kindCount }}件商品</view>
- <tui-button
- :size="24"
- width="88rpx"
- height="42rpx"
- shape="circle"
- :plain="true"
- type="base"
- @click="isDeleted = true"
- >
- 删除
- </tui-button>
- </view>
- <view class="receive-coupon">
- <view class="tip-text" v-text="couponTipText"></view>
- <tui-button
- :size="24"
- width="88rpx"
- height="42rpx"
- shape="circle"
- type="base"
- @click="visiable = true"
- >
- 领券
- </tui-button>
- </view>
- </view>
- </template>
- <view class="list-content">
- <!-- 有效商品 -->
- <view class="supplier-area" v-for="item in shopList" :key="item.shopId">
- <cm-cart-supplier-area
- :shopInfo="item"
- @change="checkedProductChange"
- @countChange="onCountChange"
- ref="supplierArea"
- ></cm-cart-supplier-area>
- </view>
- <!-- 失效商品 -->
- <view class="supplier-area" v-if="expiredProducts.length > 0">
- <cm-cart-expired-area :expiredList="expiredProducts" @clear="onClearExp"></cm-cart-expired-area>
- </view>
- </view>
- <view style="height: 100rpx;"></view>
- <!-- 购物车导航 -->
- <cm-cart-navbar
- :isCheckedAll="isChekedAll"
- :isDeleted="isDeleted"
- :data="navbarData"
- @all="onCheckedAll"
- @submit="onSumit"
- @cancel="isDeleted = false"
- @remove="removeModal = true"
- ></cm-cart-navbar>
- </template>
- <!-- 优惠券列表 -->
- <cm-coupon-popup
- :visiable="visiable"
- :list="couponList"
- :couponTabs="couponTabs"
- :hasTabs="true"
- :hasConfirm="false"
- :hasSafeArea="false"
- @close="visiable = false"
- @change="onCouponChange"
- @couponClick="onCouponClick"
- ></cm-coupon-popup>
- <!-- 确认弹框 -->
- <tui-modal :show="removeModal" content="确认删除选中的商品吗?" @click="onConfirmRemove"></tui-modal>
- <!-- 清空失效商品确认 -->
- <tui-modal :show="removeExpModal" content="确认清空失效商品?" @click="onConfirmRemoveExp"></tui-modal>
- </view>
- </template>
- <script>
- import { fetchCartInfo } from '@/services/api/cart.js'
- import { fetchCouponListByProductIds } from '@/services/api/coupon.js'
- import { arrayUnique } from '@/common/utils.js'
- import { mapGetters, mapActions } from 'vuex'
- import CouponUtils from '@/common/couponUtils.js'
- // 业务帮助函数
- import {
- totalAllCheckedProduct,
- computeTotalPrice,
- initFormatCouponList,
- makeCouponUseTip
- } from '@/common/business.helper.js'
- const resetData = () => ({
- isRequest: true,
- isDeleted: false,
- expiredProducts: [], // 失效商品列表
- shopList: [], // 供应商&&商品列表
- checkedShopMap: {},
- isChekedAll: false,
- removeModal: false,
- removeExpModal: false,
- // 商品价格
- checkedProductList: [],
- allPrice: 0, // 商品总价
- // 优惠券列表
- visiable: false,
- currentTab: 0,
- receiveCouponList: [], // 已领取优惠券
- ableCouponList: [], // 可领取优惠券
- couponTabs: [],
- currentCoupon: null,
- nextCoupon: null,
- couponTipText: '', // 可用优惠券提示
- // 保存变动
- changeRef: null
- })
- export default {
- data() {
- return resetData()
- },
- computed: {
- ...mapGetters(['userId', 'kindCount']),
- couponList() {
- return this.currentTab === 0 ? this.receiveCouponList : this.ableCouponList
- },
- navbarData() {
- const result = {
- finallyPrice: 0, // 实际应付
- couponAmount: 0,
- allPrice: 0,
- discountedPrice: 0,
- count: 0
- }
- if (this.currentCoupon) {
- result.couponAmount = this.currentCoupon.couponAmount
- result.discountedPrice = this.currentCoupon.couponAmount
- }
- result.allPrice = this.allPrice
- if (this.allPrice - result.discountedPrice > 0) {
- result.finallyPrice = this.allPrice - result.couponAmount
- }
- result.count = this.checkedProductList.length
- return result
- }
- },
- onPullDownRefresh() {
- this.resetData()
- this.fetchCartInfo()
- },
- onShow() {
- this.resetData()
- this.fetchCartInfo()
- this.fetchCartKindCount()
- },
- methods: {
- ...mapActions('cart', ['removeFromCart', 'fetchCartKindCount']),
- // 初始化数据
- resetData() {
- const data = resetData()
- for (let key in data) {
- this[key] = data[key]
- }
- },
- // 清空失效商品
- onClearExp() {
- this.removeExpModal = true
- },
- // 确认清空失效商品
- async onConfirmRemoveExp(e) {
- // removeProductFromCart
- if (!e.index) return
- try {
- await this.removeFromCart(this.expiredProducts.map(product => product.cartId))
- this.resetData()
- this.fetchCartInfo()
- } catch (e) {
- console.log('删除失效商品失败')
- } finally {
- this.removeExpModal = false
- }
- },
- // 提交订单
- onSumit() {
- if (this.checkedProductList.length <= 0) {
- return this.$toast.error('请选择商品')
- }
- const params = {}
- params.allPrice = this.allPrice
- params.allCount = this.checkedProductList.length
- params.cartIds = this.checkedProductList.map(product => product.cartId)
- params.productIds = this.checkedProductList.map(product => product.productId)
- params.productCount = ''
- uni.setStorageSync('COMMIT_CART_INFO', params)
- this.$router.navigateTo('order/order-create')
- },
- // 优惠券列表类型更换
- onCouponChange(index) {
- this.currentTab = index
- },
- // 优惠券点击事件
- onCouponClick(coupon) {
- if (coupon.controlType === 'receive') {
- this.fetchCouponList()
- } else {
- this.visiable = false
- }
- },
- // 设置couponTab数据
- makeCouponTabs() {
- return [
- {
- name: '已领取优惠券',
- num: this.receiveCouponList.length,
- isDot: false,
- disabled: false
- },
- {
- name: '可领取优惠券',
- num: this.ableCouponList.length,
- isDot: false,
- disabled: false
- }
- ]
- },
- // 获取购物车商品可用优惠券
- async fetchCouponList() {
- const productIds = []
- this.shopList.forEach(shop => shop.productList.forEach(product => productIds.push(product.productId)))
- try {
- const res = await fetchCouponListByProductIds({ userId: this.userId, productIds: productIds.join(',') })
- this.receiveCouponList = initFormatCouponList(res.data.receiveCouponList, 'search', true)
- this.ableCouponList = initFormatCouponList(res.data.ableCouponList, 'receive', true)
- this.couponTabs = this.makeCouponTabs()
- } catch (e) {
- console.log(e)
- } finally {
- this.isRequest = false
- }
- },
- // 获取购物车信息
- async fetchCartInfo() {
- try {
- const res = await fetchCartInfo({ userId: this.userId })
- this.expiredProducts = res.data.products
- this.shopList = res.data.shopList
- if (this.shopList.length > 0) {
- // 获取优惠券列表
- this.fetchCouponList()
- }
- this.isRequest = false
- return res
- } catch (e) {
- return e
- } finally {
- uni.stopPullDownRefresh()
- }
- },
- // 确认删除
- async onConfirmRemove({ index }) {
- if (!index) return (this.removeModal = false)
- const cartIds = this.checkedProductList.map(product => product.cartId)
- try {
- await this.removeFromCart(cartIds)
- this.fetchCartInfo()
- } catch (e) {
- console.log(e)
- } finally {
- this.isDeleted = false
- this.removeModal = false
- }
- },
- // 选中/取消全部商品
- onCheckedAll() {
- if (this.isChekedAll) {
- this.$refs.supplierArea.forEach(item => item.unSelectAll())
- } else {
- this.$refs.supplierArea.forEach(item => item.selectAll())
- }
- },
- // 选中商品变化
- checkedProductChange(e) {
- this.changeRef = e
- this.handleCartManager()
- },
- // 修改商品checked属性
- updatePorudctChecked(row) {
- const shopInfo = this.shopList.find(item => row.shopId === item.shopId)
- if (!shopInfo) return
- shopInfo.productList.forEach(item => {
- if (row.checkedList.includes(item.productId.toString())) {
- this.$set(item, 'checked', true)
- } else {
- this.$set(item, 'checked', false)
- }
- })
- },
- // 购物车数据处理器
- handleCartManager() {
- if (!this.changeRef) return
- this.updatePorudctChecked(this.changeRef)
- // 保存选中商品id与供应商id的k-v关系
- this.$set(this.checkedShopMap, this.changeRef.shopId, this.changeRef.checkedList)
- this.isChekedAll = this.validateIsChekedAll()
- // 获取已选商品列表
- this.checkedProductList = totalAllCheckedProduct(this.shopList)
- // 计算商品总价
- this.allPrice = computeTotalPrice(this.checkedProductList)
- const couponUtils = new CouponUtils(this.receiveCouponList, this.checkedProductList)
- this.currentCoupon = couponUtils.bestCoupon
- this.nextCoupon = couponUtils.secondCoupon
- this.couponTipText = makeCouponUseTip(this.currentCoupon, this.nextCoupon, this.allPrice)
- },
- // 商品数量变化
- async onCountChange(e) {
- await this.$store.dispatch('cart/updateProductCount', {
- cartId: e.cartId,
- productCount: e.count
- })
- await this.fetchCartInfo()
- this.handleCartManager()
- },
- // 验证是否全选
- validateIsChekedAll() {
- return this.shopList.every(item => {
- const checkedList = this.checkedShopMap[item.shopId] || []
- return item.productList.length === checkedList.length
- })
- }
- }
- }
- </script>
- <style scoped lang="scss">
- .goods-total {
- @extend .cm-flex-between;
- background: #f7f7f7;
- padding: 0 24rpx;
- height: 80rpx;
- .total {
- font-size: 30rpx;
- color: #333;
- }
- }
- .receive-coupon {
- @extend .cm-flex-between;
- background: #fff;
- padding: 0 24rpx;
- height: 80rpx;
- .tip-text {
- font-size: 26rpx;
- color: #ff457b;
- white-space: nowrap;
- overflow: hidden;
- text-overflow: ellipsis;
- }
- }
- .supplier-area {
- margin-bottom: 24rpx;
- }
- </style>
|