fix: 按主流电商标准重构购物车移动端布局

布局结构(参考京东/淘宝):
┌──────────────────────────────────────────────────┐
│ [☑] [图片] 商品名称...                  [删除]  │
│            标签                                   │
│            ¥价格                  [数量选择器]   │
└──────────────────────────────────────────────────┘

- 复选框+图片+内容三列布局
- 商品名称和删除按钮在同一行
- 价格和数量选择器在底部行
- 桌面端和移动端完全分离的DOM结构
- 各元素位置清晰,不会错位

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-01 18:48:58 +08:00
parent 730e12e9b9
commit 137e221f4a
+104 -88
View File
@@ -28,8 +28,10 @@
class="cart-item"
:class="{ 'item-disabled': !item.product?.is_active }"
>
<!-- 复选框 -->
<el-checkbox v-model="selectedIds" :value="item.id" class="item-check" />
<!-- 桌面端商品信息 -->
<div class="item-product" @click="$router.push(`/products/${item.product?.id}`)">
<el-image
:src="getFirstImage(item.product?.images)"
@@ -54,25 +56,51 @@
</div>
<p v-if="!item.product?.is_active" class="item-off">已下架</p>
</div>
</div>
<!-- 移动端底部价格 + 数量 -->
<div class="item-mobile-bottom">
<div class="mobile-price-row">
<span class="mobile-price">¥{{ item.product?.price }}</span>
</div>
<div class="mobile-quantity-row">
<el-input-number
v-model="item.quantity"
:min="1"
:max="getMaxQuantity(item.product)"
size="small"
controls-position="right"
@change="(val: number) => updateQuantity(item, val)"
/>
</div>
<!-- 移动端商品图片 -->
<div class="item-image-wrap" @click="$router.push(`/products/${item.product?.id}`)">
<el-image
:src="getFirstImage(item.product?.images)"
fit="cover"
class="item-image"
>
<template #error>
<div class="image-placeholder">
<el-icon><Picture /></el-icon>
</div>
</template>
</el-image>
</div>
<!-- 移动端商品信息区 -->
<div class="item-content">
<div class="item-header">
<h4 class="item-name" @click="$router.push(`/products/${item.product?.id}`)">{{ item.product?.name }}</h4>
<el-button class="item-delete" link type="danger" size="small" @click="removeItem(item.id)">删除</el-button>
</div>
<div class="item-tags" v-if="item.product?.require_credit || item.product?.credit_reward > 0">
<el-tag v-if="item.product?.require_credit" size="small" type="warning">
需要: {{ item.product?.credit_cost }}
</el-tag>
<el-tag v-if="item.product?.credit_reward > 0" size="small" type="success">
+{{ item.product?.credit_reward }}
</el-tag>
</div>
<p v-if="!item.product?.is_active" class="item-off">已下架</p>
<div class="item-footer">
<span class="item-price-mobile">¥{{ item.product?.price }}</span>
<el-input-number
v-model="item.quantity"
:min="1"
:max="getMaxQuantity(item.product)"
size="small"
@change="(val: number) => updateQuantity(item, val)"
/>
</div>
</div>
<!-- 桌面端元素 -->
<div class="item-price">
<span class="price-current">¥{{ item.product?.price }}</span>
</div>
@@ -555,7 +583,7 @@ onMounted(() => {
}
> .el-checkbox { width: 60px; flex-shrink: 0; }
> .item-product { flex: 1; min-width: 200px; }
> .item-product { flex: 1; min-width: 200px; display: flex; gap: 12px; }
> .item-price { width: 100px; text-align: center; flex-shrink: 0; }
> .item-quantity { width: 140px; display: flex; flex-direction: column; align-items: center; gap: 4px; flex-shrink: 0; }
> .item-subtotal { width: 100px; text-align: center; flex-shrink: 0; }
@@ -570,6 +598,15 @@ onMounted(() => {
align-items: flex-start;
}
/* 移动端专用元素 - 桌面端隐藏 */
.item-image-wrap {
display: none;
}
.item-content {
display: none;
}
.item-image {
width: 70px;
height: 70px;
@@ -998,13 +1035,13 @@ onMounted(() => {
gap: 10px !important;
}
/* 商品项 - 京东风格卡片布局 */
/* 商品项 - 主流电商布局 */
.cart-item {
display: flex !important;
flex-direction: row !important;
padding: 12px !important;
gap: 10px !important;
align-items: stretch !important;
align-items: flex-start !important;
width: 100% !important;
box-sizing: border-box !important;
background: #2d2d44 !important;
@@ -1013,136 +1050,115 @@ onMounted(() => {
}
/* 隐藏桌面端元素 */
.cart-item > .item-product,
.cart-item > .item-price,
.cart-item > .item-quantity,
.cart-item > .item-subtotal {
.cart-item > .item-subtotal,
.cart-item > .item-action {
display: none !important;
}
/* 复选框 - 左侧垂直居中 */
/* 复选框 */
.cart-item > .item-check {
flex: 0 0 20px !important;
width: 20px !important;
margin-right: 0 !important;
align-self: center !important;
align-self: flex-start !important;
margin-top: 2px !important;
}
/* 商品信息区 - 中间主体 */
.cart-item > .item-product {
flex: 1 1 0 !important;
min-width: 0 !important;
display: flex !important;
flex-direction: row !important;
flex-wrap: wrap !important;
gap: 8px !important;
align-items: flex-start !important;
cursor: pointer !important;
/* 移动端商品图片 */
.cart-item > .item-image-wrap {
display: block !important;
flex: 0 0 80px !important;
width: 80px !important;
}
/* 删除按钮 - 右上角绝对定位 */
.cart-item > .item-action {
position: absolute !important;
right: 8px !important;
top: 8px !important;
z-index: 10 !important;
}
/* 商品图片 */
.item-product .item-image {
.item-image-wrap .item-image {
width: 80px !important;
height: 80px !important;
flex-shrink: 0 !important;
border-radius: 4px !important;
}
/* 商品信息区 - 图片右侧 */
.item-info {
flex: 1 1 calc(100% - 100px) !important;
/* 移动端商品信息区 */
.cart-item > .item-content {
display: flex !important;
flex: 1 1 0 !important;
min-width: 0 !important;
max-width: calc(100% - 100px) !important;
overflow: hidden !important;
padding-right: 30px !important;
flex-direction: column !important;
gap: 6px !important;
}
.item-name {
/* 商品名称行 + 删除按钮 */
.item-content .item-header {
display: flex !important;
justify-content: space-between !important;
align-items: flex-start !important;
gap: 8px !important;
}
.item-content .item-name {
flex: 1 !important;
font-size: 14px !important;
line-height: 1.4 !important;
margin-bottom: 4px !important;
margin: 0 !important;
color: #fff !important;
word-break: break-all !important;
display: -webkit-box !important;
-webkit-line-clamp: 2 !important;
-webkit-box-orient: vertical !important;
overflow: hidden !important;
color: #fff !important;
}
.item-tags {
.item-content .item-delete {
flex-shrink: 0 !important;
font-size: 12px !important;
padding: 0 !important;
}
/* 标签 */
.item-content .item-tags {
display: flex !important;
flex-wrap: wrap !important;
gap: 4px !important;
margin-top: 2px !important;
}
.item-tags .el-tag {
.item-content .item-tags .el-tag {
font-size: 10px !important;
padding: 0 4px !important;
height: 16px !important;
line-height: 14px !important;
}
/* 移动端底部 - 价格和数量 */
.item-mobile-bottom {
/* 价格 + 数量 */
.item-content .item-footer {
display: flex !important;
align-items: center !important;
justify-content: space-between !important;
width: 100% !important;
flex: 0 0 100% !important;
padding-left: 0 !important;
margin-top: 8px !important;
align-items: center !important;
margin-top: auto !important;
}
.mobile-price-row {
display: flex !important;
align-items: baseline !important;
}
.item-mobile-bottom .mobile-price {
.item-content .item-price-mobile {
font-size: 16px !important;
font-weight: 600 !important;
color: #f2270c !important;
white-space: nowrap !important;
}
.mobile-quantity-row {
display: flex !important;
align-items: center !important;
.item-content .item-footer :deep(.el-input-number) {
width: 100px !important;
}
.item-mobile-bottom :deep(.el-input-number) {
width: 90px !important;
.item-content .item-footer :deep(.el-input-number .el-input__wrapper) {
padding: 0 4px !important;
}
.item-mobile-bottom :deep(.el-input-number .el-input__wrapper) {
padding: 0 28px 0 8px !important;
background: rgba(255,255,255,0.08) !important;
border-radius: 4px !important;
}
.item-mobile-bottom :deep(.el-input-number .el-input__inner) {
.item-content .item-footer :deep(.el-input-number .el-input__inner) {
font-size: 13px !important;
text-align: left !important;
}
/* 删除按钮样式 */
.item-action .el-button {
font-size: 12px !important;
padding: 2px 4px !important;
}
/* 地址 */
.checkout-section {
padding: 12px !important;
margin-top: 0 !important;
border-radius: 8px !important;
}