290 lines
7.4 KiB
Vue
290 lines
7.4 KiB
Vue
<template>
|
|
<view class="cart-page">
|
|
<!-- 自定义导航栏 -->
|
|
<view class="navbar" :style="{ paddingTop: statusBarHeight + 'px' }">
|
|
<view class="navbar__content" :style="{ height: navBarHeight + 'px' }">
|
|
<text class="navbar__title">购物车</text>
|
|
</view>
|
|
</view>
|
|
<!-- 占位 -->
|
|
<view :style="{ height: (statusBarHeight + navBarHeight) + 'px' }"></view>
|
|
|
|
<!-- 购物车列表 -->
|
|
<view v-if="cartStore.items.length > 0" class="cart-list">
|
|
<view v-for="item in cartStore.items" :key="item.id" class="cart-item">
|
|
<!-- 复选框 -->
|
|
<view class="cart-item__check" @click="cartStore.toggleCheck(item.id)">
|
|
<image class="check-icon" :src="item.checked ? '/static/ic_check_s.png' : '/static/ic_check.png'" mode="aspectFit" />
|
|
</view>
|
|
<!-- 内容区 -->
|
|
<view class="cart-item__body">
|
|
<!-- 上部:图片 + 信息 -->
|
|
<view class="cart-item__top">
|
|
<image class="cart-item__img" :src="fullUrl(item.product?.thumb || item.product?.bannerImages?.[0] || '')" mode="aspectFill" />
|
|
<view class="cart-item__info">
|
|
<text class="cart-item__name">{{ item.product?.name || item.specData?.modelName }}</text>
|
|
<view class="cart-item__specs">
|
|
<text class="spec-tag">款号:{{ item.product?.styleNo }}</text>
|
|
<text class="spec-tag">条码号:{{ item.specData?.modelName }}</text>
|
|
<text class="spec-tag">镶口:{{ item.specData?.ringSize }}</text>
|
|
<text class="spec-tag">分手寸:{{ item.specData?.ringSize }}</text>
|
|
<text class="spec-tag">金重:{{ item.specData?.goldTotalWeight }}g</text>
|
|
<text class="spec-tag">{{ item.specData?.fineness }}</text>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
<!-- 下部:价格 + 删除 -->
|
|
<view class="cart-item__bottom">
|
|
<text class="cart-item__price">¥{{ item.specData?.totalPrice || 0 }}元</text>
|
|
<text class="cart-item__delete" @click="cartStore.removeFromCart(item.id)">删除</text>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 空状态 -->
|
|
<view v-else class="empty-cart">
|
|
<image class="empty-cart__icon" src="/static/ic_none.png" mode="aspectFit" />
|
|
<text class="empty-cart__text">购物车是空的</text>
|
|
</view>
|
|
|
|
<!-- 底部结算栏 -->
|
|
<view v-if="cartStore.items.length > 0" class="settle-bar">
|
|
<view class="settle-bar__left" @click="cartStore.toggleCheckAll()">
|
|
<image class="check-icon" :src="isAllChecked ? '/static/ic_check_s.png' : '/static/ic_check.png'" mode="aspectFit" />
|
|
<text class="settle-bar__all-text">全选</text>
|
|
</view>
|
|
<view class="settle-bar__right">
|
|
<view class="settle-bar__total">
|
|
<text class="settle-bar__total-label">合计:</text>
|
|
<text class="settle-bar__price">¥{{ cartStore.totalAmount.toFixed(2) }}</text>
|
|
</view>
|
|
<view
|
|
class="settle-bar__btn"
|
|
:class="{ 'settle-bar__btn--disabled': cartStore.checkedItems.length === 0 }"
|
|
@click="handleSettle"
|
|
>开始下单</view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { ref, computed, onMounted } from 'vue'
|
|
import { useCartStore } from '../../store/cart'
|
|
import { BASE_URL } from '../../utils/request'
|
|
import type { CartItem } from '../../types'
|
|
|
|
function fullUrl(path: string): string {
|
|
if (!path) return ''
|
|
if (path.startsWith('http')) return path
|
|
return BASE_URL + path
|
|
}
|
|
|
|
const cartStore = useCartStore()
|
|
|
|
const statusBarHeight = ref(0)
|
|
const navBarHeight = ref(44)
|
|
|
|
const isAllChecked = computed(() =>
|
|
cartStore.items.length > 0 && cartStore.items.every((item) => item.checked),
|
|
)
|
|
|
|
onMounted(() => {
|
|
const sysInfo = uni.getSystemInfoSync()
|
|
statusBarHeight.value = sysInfo.statusBarHeight || 0
|
|
const menuBtn = uni.getMenuButtonBoundingClientRect()
|
|
navBarHeight.value = menuBtn.height + (menuBtn.top - (sysInfo.statusBarHeight || 0)) * 2
|
|
|
|
cartStore.fetchCart()
|
|
})
|
|
|
|
function handleMinus(item: CartItem) {
|
|
if (item.quantity > 1) {
|
|
cartStore.updateQuantity(item.id, item.quantity - 1)
|
|
}
|
|
}
|
|
|
|
function handleSettle() {
|
|
if (cartStore.checkedItems.length === 0) {
|
|
uni.showToast({ title: '请先选择商品', icon: 'none' })
|
|
return
|
|
}
|
|
const token = uni.getStorageSync('token')
|
|
if (!token) {
|
|
uni.navigateTo({ url: '/pages/login/index' })
|
|
return
|
|
}
|
|
uni.navigateTo({ url: '/pages/order/submit' })
|
|
}
|
|
|
|
function goHome() {
|
|
uni.switchTab({ url: '/pages/index/index' })
|
|
}
|
|
</script>
|
|
|
|
<style scoped>
|
|
.cart-page {
|
|
min-height: 100vh;
|
|
background: #f5f5f5;
|
|
padding-bottom: calc(120rpx + env(safe-area-inset-bottom));
|
|
}
|
|
|
|
/* 导航栏 */
|
|
.navbar {
|
|
position: fixed; top: 0; left: 0; right: 0; z-index: 100;
|
|
background: linear-gradient(to right, #FFCFDE, #FFA6C4);
|
|
}
|
|
.navbar__content {
|
|
display: flex; align-items: center; justify-content: center;
|
|
}
|
|
.navbar__title {
|
|
font-size: 34rpx; font-weight: 600; color: #333;
|
|
}
|
|
|
|
/* 购物车列表 */
|
|
.cart-list {
|
|
padding: 16rpx 20rpx;
|
|
}
|
|
.cart-item {
|
|
display: flex;
|
|
align-items: center;
|
|
background: #fff;
|
|
border-radius: 16rpx;
|
|
padding: 28rpx 20rpx;
|
|
margin-bottom: 16rpx;
|
|
}
|
|
.cart-item__check {
|
|
margin-right: 16rpx;
|
|
flex-shrink: 0;
|
|
}
|
|
.check-icon {
|
|
width: 44rpx;
|
|
height: 44rpx;
|
|
}
|
|
.cart-item__body {
|
|
flex: 1;
|
|
min-width: 0;
|
|
}
|
|
.cart-item__top {
|
|
display: flex;
|
|
}
|
|
.cart-item__img {
|
|
width: 200rpx;
|
|
height: 200rpx;
|
|
border-radius: 16rpx;
|
|
margin-right: 24rpx;
|
|
flex-shrink: 0;
|
|
}
|
|
.cart-item__info {
|
|
flex: 1;
|
|
min-width: 0;
|
|
}
|
|
.cart-item__name {
|
|
font-size: 32rpx;
|
|
color: #333;
|
|
font-weight: 700;
|
|
display: -webkit-box;
|
|
-webkit-line-clamp: 1;
|
|
-webkit-box-orient: vertical;
|
|
overflow: hidden;
|
|
margin-bottom: 14rpx;
|
|
}
|
|
.cart-item__specs {
|
|
display: grid;
|
|
grid-template-columns: 1fr 1fr;
|
|
gap: 6rpx 20rpx;
|
|
}
|
|
.spec-tag {
|
|
font-size: 24rpx;
|
|
color: #666;
|
|
line-height: 1.7;
|
|
}
|
|
.cart-item__bottom {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
margin-top: 16rpx;
|
|
}
|
|
.cart-item__price {
|
|
font-size: 34rpx;
|
|
color: #e91e63;
|
|
font-weight: bold;
|
|
}
|
|
.cart-item__delete {
|
|
font-size: 24rpx;
|
|
color: #bbb;
|
|
padding: 8rpx 0;
|
|
}
|
|
|
|
/* 空状态 */
|
|
.empty-cart {
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
justify-content: center;
|
|
padding-top: 280rpx;
|
|
}
|
|
.empty-cart__icon {
|
|
width: 360rpx;
|
|
height: 360rpx;
|
|
margin-bottom: 32rpx;
|
|
}
|
|
.empty-cart__text {
|
|
font-size: 30rpx;
|
|
color: #bbb;
|
|
}
|
|
|
|
/* 底部结算栏 */
|
|
.settle-bar {
|
|
position: fixed;
|
|
bottom: 0;
|
|
left: 0;
|
|
right: 0;
|
|
background: #fff;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
padding: 16rpx 24rpx;
|
|
box-shadow: 0 -2rpx 16rpx rgba(0, 0, 0, 0.06);
|
|
}
|
|
.settle-bar__left {
|
|
display: flex;
|
|
align-items: center;
|
|
}
|
|
.settle-bar__all-text {
|
|
font-size: 26rpx;
|
|
color: #333;
|
|
margin-left: 10rpx;
|
|
}
|
|
.settle-bar__right {
|
|
display: flex;
|
|
align-items: center;
|
|
}
|
|
.settle-bar__total {
|
|
margin-right: 20rpx;
|
|
display: flex;
|
|
align-items: baseline;
|
|
}
|
|
.settle-bar__total-label {
|
|
font-size: 26rpx;
|
|
color: #666;
|
|
}
|
|
.settle-bar__price {
|
|
color: #e91e63;
|
|
font-weight: bold;
|
|
font-size: 38rpx;
|
|
}
|
|
.settle-bar__btn {
|
|
background: linear-gradient(to right, #FFB6C8, #FF6D9B);
|
|
color: #fff;
|
|
font-size: 28rpx;
|
|
padding: 18rpx 48rpx;
|
|
border-radius: 44rpx;
|
|
font-weight: 500;
|
|
}
|
|
.settle-bar__btn--disabled {
|
|
background: linear-gradient(to right, #ddd, #ccc);
|
|
}
|
|
</style>
|