diff --git a/yshop-drink-uniapp-vue3/pages/menu/menu.vue b/yshop-drink-uniapp-vue3/pages/menu/menu.vue index f84c0dc..0127b87 100644 --- a/yshop-drink-uniapp-vue3/pages/menu/menu.vue +++ b/yshop-drink-uniapp-vue3/pages/menu/menu.vue @@ -127,11 +127,11 @@ - + @@ -210,22 +210,30 @@ - - + + @@ -339,22 +349,18 @@ let deliveryFeeReqId = 0 const measureMenuLayout = () => { } -const goodCartNum = computed(() => { //计算单个饮品添加到购物车的数量 - return (id) => cart.value.reduce((acc, cur) => { - if (cur.id === id) { - return acc += cur.number - } - return acc - }, 0) -}) -const menuCartNum = computed(() =>{ - return (id) => cart.value.reduce((acc, cur) => { - if (cur.cate_id === id) { - return acc += cur.number - } - return acc - }, 0) +// 一次遍历生成角标映射,避免列表里每个商品反复 reduce +const cartNumMaps = computed(() => { + const byGood = Object.create(null) + const byCate = Object.create(null) + for (const item of cart.value) { + byGood[item.id] = (byGood[item.id] || 0) + item.number + byCate[item.cate_id] = (byCate[item.cate_id] || 0) + item.number + } + return { byGood, byCate } }) +const goodCartNum = computed(() => (id) => cartNumMaps.value.byGood[id] || 0) +const menuCartNum = computed(() => (id) => cartNumMaps.value.byCate[id] || 0) const getCartGoodsNumber = computed(() => { //计算购物车总数 return cart.value.reduce((acc, cur) => acc + cur.number, 0) }) @@ -363,12 +369,15 @@ const getCartGoodsPrice = computed(() =>{ //计算购物车总价 return parseFloat(price).toFixed(2); }) const disabledPay = computed(() => { //是否达到起送价 - return orderType.value == 'takeout' && (getCartGoodsPrice < parseFloat(store.value.minPrice)) ? true : - false + const amount = parseFloat(getCartGoodsPrice.value) || 0 + const minPrice = parseFloat(store.value?.minPrice) || 0 + return orderType.value == 'takeout' && minPrice > 0 && amount < minPrice }) const spread = computed(() => { //差多少元起送 - if (orderType.value != 'takeout') return - return parseFloat((store.value.minPrice - getCartGoodsPrice).toFixed(2)) + if (orderType.value != 'takeout') return 0 + const amount = parseFloat(getCartGoodsPrice.value) || 0 + const minPrice = parseFloat(store.value?.minPrice) || 0 + return parseFloat(Math.max(0, minPrice - amount).toFixed(2)) }) const freeDeliveryAmount = computed(() => parseFloat(store.value?.freeDeliveryAmount) || 0) const lowestDeliveryFee = computed(() => { @@ -625,17 +634,20 @@ const refreshCart = () =>{ let newCart = uni.getStorageSync('cart') || []; let tmpCart = []; if (newCart) { - for (let i in newCart) { - for (let ii in newGoods) { - for (let iii in newGoods[ii].goodsList) { - if (newCart[i].id == newGoods[ii].goodsList[iii].id) { - tmpCart.push(newCart[i]); - } - } + const goodsIdSet = new Set() + for (const cate of newGoods) { + for (const g of (cate.goodsList || [])) { + goodsIdSet.add(g.id) } } + for (const item of newCart) { + if (goodsIdSet.has(item.id)) tmpCart.push(item) + } cart.value = tmpCart; - cartPopupVisible.value = false; + if (!tmpCart.length && cartPopupVisible.value) { + cartPopupVisible.value = false + popup.value?.close?.() + } } } refreshMenuDeliveryFee() @@ -893,11 +905,15 @@ const handleAddToCartInModal = () => { handleAddToCart(category.value, good.value, good.value.number) closeGoodDetailModal() } -const openCartPopup = () => { //打开/关闭购物车列表popup +const openCartPopup = () => { //打开购物车列表popup isCartShow.value = true if (!cart.value.length) return + cartPopupVisible.value = true popup.value.open() } +const onCartPopupChange = (e) => { + cartPopupVisible.value = !!e?.show +} const handleCartClear = () => { //清空购物车 uni.showModal({ title: '提示', @@ -907,8 +923,9 @@ const handleCartClear = () => { //清空购物车 }) => { if (confirm) { popup.value.close() + cartPopupVisible.value = false cart.value = [] - uni.setStorageSync('cart', JSON.parse(JSON.stringify(cart.value))) + uni.setStorageSync('cart', []) } } }) @@ -1592,7 +1609,7 @@ page { /* #endif */ left: $spacing-row-lg; right: $spacing-row-lg; - z-index: 9999; + z-index: 999; display: flex; align-items: center; justify-content: space-between; @@ -1676,12 +1693,29 @@ page { } .cart-popup { + overflow: hidden; + border-radius: 24rpx 24rpx 0 0; + background: #fff; + .top { - padding: $menu-gap-sm $spacing-row-lg; + display: flex; + align-items: center; + justify-content: space-between; + padding: 28rpx $spacing-row-lg 20rpx; font-size: $font-size-sm; - text-align: right; color: $menu-secondary-color; - background-color: $bg-color-primary; + background-color: #fffaf5; + + &__title { + font-size: 28rpx; + font-weight: 700; + color: #2b201a; + } + + &__clear { + padding: 8rpx 0 8rpx 24rpx; + color: #a8907a; + } } .cart-list { @@ -1694,7 +1728,6 @@ page { .wrapper { display: flex; flex-direction: column; - height: 100%; padding: 0 $spacing-row-lg; margin-bottom: $menu-gap-base; @@ -1702,38 +1735,53 @@ page { position: relative; display: flex; align-items: center; - justify-content: space-between; padding: $spacing-row-lg 0; @include list-divider; + .thumb { + flex: 0 0 96rpx; + width: 96rpx; + height: 96rpx; + margin-right: 20rpx; + border-radius: 16rpx; + background: #fff5eb; + } + .left { flex: 1; display: flex; flex-direction: column; + min-width: 0; margin-right: $spacing-row-lg; overflow: hidden; .name { - font-size: $font-size-sm; + font-size: 28rpx; + font-weight: 600; color: $text-color-base; + @include text-ellipsis; } .props { + margin-top: 4rpx; font-size: $font-size-sm; color: $text-color-assist; @include text-ellipsis; } - } - .center { - margin-right: $menu-cart-price-offset; - font-size: $font-size-base; + .unit-price { + margin-top: 8rpx; + font-size: 28rpx; + font-weight: 700; + color: #ff6817; + } } .right { + flex: 0 0 auto; display: flex; align-items: center; - justify-content: space-between; + justify-content: flex-end; @include quantity-control(var(--menu-control-size)); .btn { @@ -1746,38 +1794,27 @@ page { .cart-footer { display: flex; - align-items: center; - justify-content: space-between; + flex-direction: column; padding: $menu-gap-base $spacing-row-lg; background-color: $text-color-white; - border-top: 1rpx solid $border-color; + border-top: 1rpx solid #f0ebe6; + box-shadow: 0 -8rpx 24rpx rgba(91, 61, 32, 0.06); .summary { - flex: 1; - min-width: 0; - margin-right: $spacing-row-lg; + width: 100%; + margin-bottom: 16rpx; .row { display: flex; align-items: center; justify-content: space-between; font-size: $font-size-sm; - line-height: 1.5; + line-height: 1.6; color: $text-color-base; .value.free { color: $color-primary; } - - &.total { - margin-top: 4rpx; - font-weight: 700; - - .value { - font-size: 32rpx; - color: $color-primary; - } - } } .tip { @@ -1788,13 +1825,51 @@ page { } } + .checkout-row { + display: flex; + align-items: center; + justify-content: space-between; + gap: 20rpx; + } + + .checkout-total { + display: flex; + align-items: baseline; + min-width: 0; + + &__label { + margin-right: 8rpx; + font-size: 24rpx; + color: #7c756e; + } + + &__yen { + font-size: 26rpx; + font-weight: 700; + color: #ff6817; + } + + &__value { + font-size: 40rpx; + font-weight: 700; + line-height: 1; + color: #ff6817; + } + } + .checkout-btn { flex: 0 0 auto; - height: 72rpx; + height: 80rpx; padding: 0 48rpx; font-size: $font-size-base; - line-height: 72rpx; - border-radius: 36rpx; + line-height: 80rpx; + border-radius: 40rpx; + background: linear-gradient(90deg, #ff9b20, #ff6817); + border: none; + + &[disabled] { + opacity: 0.55; + } } } } @@ -1859,7 +1934,17 @@ page { .goods .wrapper .list .category .items .good .right .name { font-size: 31rpx; font-weight: 700; } .goods .wrapper .list .category .items .good .right .price_and_action .price { font-size: 36rpx; color: #ff6817; } .goods .wrapper .list .category .items .good .right .price_and_action .btn-group .btn.property_btn { height: 56rpx; padding: 0 18rpx; line-height: 56rpx; border-radius: 28rpx; background: #ff7417; } - .cart-box { bottom: 28rpx; min-height: 116rpx; height: auto; border-radius: 58rpx; box-shadow: 0 8rpx 28rpx rgba(91, 61, 32, .16); } + .cart-box { + bottom: 28rpx; + /* #ifdef H5 */ + /* 贴在 tabBar 上方,只保留 28rpx 间距,勿再叠加 safe-area */ + bottom: calc(var(--window-bottom, 0px) + 28rpx); + /* #endif */ + min-height: 116rpx; + height: auto; + border-radius: 58rpx; + box-shadow: 0 8rpx 28rpx rgba(91, 61, 32, .16); + } .cart-box .cart-img { width: 116rpx; height: 116rpx; } .cart-box .pay-btn { padding: 0 46rpx; border-radius: 58rpx; background: linear-gradient(90deg, #ff9b20, #ff6817); } .cart-box .price__tip { color: #b08968; } @@ -1912,4 +1997,8 @@ page { .cart-popup .right .btn[type='default'] { color: #ff7417; border-color: #ff7417; } .cart-popup .right .btn[type='primary'] { background: #ff7417; } +.cart-popup .checkout-btn[type='primary'] { + background: linear-gradient(90deg, #ff9b20, #ff6817); + border-color: transparent; +}