Files
nl-mall/src/components/ShoppingCartDrawer.vue
2025-05-29 16:58:38 +08:00

213 lines
6.4 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>
<el-drawer
v-model="drawerVisible"
title="购物车"
direction="rtl"
size="400px"
>
<div class="cart-content h-full flex flex-col">
<!-- 购物车列表 -->
<div class="cart-items flex-1 overflow-y-auto p-4">
<div v-if="items.length === 0" class="empty-cart text-center py-8">
<div class="text-6xl mb-4">🛒</div>
<p class="text-gray-500">购物车是空的</p>
<el-button type="primary" @click="drawerVisible = false" class="mt-4">
去购物
</el-button>
</div>
<div v-else class="space-y-4">
<div
v-for="(item, index) in items"
:key="`${item.productId}-${item.color}-${item.size}`"
class="cart-item p-4 border border-gray-200 rounded-lg shadow-sm transition duration-300 ease-in-out hover:shadow-md"
>
<div class="flex space-x-3">
<!-- 商品图片 -->
<img
:src="item.cover"
:alt="item.title"
class="w-16 h-16 object-cover rounded"
>
<!-- 商品信息 -->
<div class="flex-1 min-w-0">
<h4 class="font-medium text-sm line-clamp-2 mb-1">{{ item.title }}</h4>
<div class="text-xs text-gray-500 mb-2">
{{ item.color }} / {{ item.size }}
</div>
<div class="flex items-center justify-between">
<span class="text-red-600 font-bold">¥{{ item.price }}</span>
<!-- 数量控制 -->
<div class="flex items-center space-x-2">
<el-button
size="small"
@click="updateQuantity(index, item.quantity - 1)"
:disabled="item.quantity <= 1"
>
-
</el-button>
<span class="w-8 text-center">{{ item.quantity }}</span>
<el-button
size="small"
@click="updateQuantity(index, item.quantity + 1)"
>
+
</el-button>
</div>
</div>
</div>
<!-- 删除按钮 -->
<el-button
text
type="danger"
@click="removeItem(index)"
class="self-start"
>
<el-icon><Delete /></el-icon>
</el-button>
</div>
</div>
</div>
</div>
<!-- 底部结算 -->
<div v-if="items.length > 0" class="cart-footer border-t pt-4 mt-4 p-4">
<!-- 优惠信息 -->
<div class="discount-info mb-4 p-3 bg-yellow-50 rounded-lg shadow-sm">
<div class="flex items-center justify-between text-sm">
<span>满减优惠</span>
<span class="text-orange-600">-¥{{ discountAmount }}</span>
</div>
<div class="text-xs text-gray-500 mt-1">
{{ discountThreshold }}元减{{ discountAmount }}
</div>
</div>
<!-- 总计 -->
<div class="total-section mb-4">
<div class="flex justify-between items-center mb-2">
<span>商品总计</span>
<span class="text-red-600">¥{{ subtotal }}</span>
</div>
<div class="flex justify-between items-center mb-2">
<span>运费</span>
<span class="text-green-600">{{ shippingFee === 0 ? '免运费' : `¥${shippingFee}` }}</span>
</div>
<div class="flex justify-between items-center mb-2">
<span>优惠</span>
<span class="text-orange-600">-¥{{ discountAmount }}</span>
</div>
<div class="flex justify-between items-center text-lg font-bold border-t pt-2">
<span>总计</span>
<span class="text-red-600">¥{{ finalTotal }}</span>
</div>
</div>
<!-- 结算按钮 -->
<el-button
type="primary"
size="large"
class="w-full py-3 rounded-lg shadow-md hover:shadow-lg transition duration-300 ease-in-out"
@click="handleCheckout"
>
去结算 ({{ totalQuantity }})
</el-button>
<!-- 继续购物 -->
<el-button
size="large"
class="w-full py-3 mt-2 rounded-lg border border-gray-300 hover:border-red-300 hover:text-red-600 transition duration-300 ease-in-out"
@click="drawerVisible = false"
>
继续购物
</el-button>
</div>
</div>
</el-drawer>
</template>
<script setup>
import { computed } from 'vue'
import { Delete } from '@element-plus/icons-vue'
const props = defineProps({
visible: {
type: Boolean,
default: false
},
items: {
type: Array,
default: () => []
}
})
const emit = defineEmits(['update:visible', 'checkout', 'update-quantity', 'remove-item'])
const drawerVisible = computed({
get: () => props.visible,
set: (value) => emit('update:visible', value)
})
// 计算总数量
const totalQuantity = computed(() => {
return props.items.reduce((total, item) => total + item.quantity, 0)
})
// 计算小计
const subtotal = computed(() => {
return props.items.reduce((total, item) => total + item.price * item.quantity, 0).toFixed(2)
})
// 运费计算
const shippingFee = computed(() => {
return parseFloat(subtotal.value) >= 99 ? 0 : 10
})
// 优惠计算
const discountThreshold = 200
const discountAmount = computed(() => {
return parseFloat(subtotal.value) >= discountThreshold ? 20 : 0
})
// 最终总计
const finalTotal = computed(() => {
const total = parseFloat(subtotal.value) + shippingFee.value - discountAmount.value
return Math.max(0, total).toFixed(2)
})
const updateQuantity = (index, quantity) => {
emit('update-quantity', index, quantity)
}
const removeItem = (index) => {
emit('remove-item', index)
}
const handleCheckout = () => {
emit('checkout')
}
</script>
<style lang="scss" scoped>
.cart-item:hover {
@apply border-red-300;
}
.empty-cart {
@apply text-gray-400;
}
.el-button--primary {
background-color: #dc3545;
border-color: #dc3545;
color: white;
}
.el-button--primary:hover {
background-color: #c82333;
border-color: #bd2130;
}
</style>