购物车 — 前端技术方案(C 端 · shop-app)
依据: 《购物车功能需求.md》v1.0、《购物车技术方案.md》v1.0(仅作接口对照,本文档独立维护)
关联: 《商品详情内页前端技术方案》、《确认订单页(多商品)前端技术方案》v1.0、《店铺主页前端技术方案》
范围: C 端 购物车 Tab 列表、详情 加购、勾选/改量/删除/清理失效、同店去结算;确认订单 多商品页 见另册,本模块负责跳转与 prepare 门禁。
实现状态: Tab 页、组件、API、checkout-cart 跳转链路 已落地。
1. 技术栈与约定
| 项 |
说明 |
| 框架 |
uni-app Vue 3 + uview-plus |
| 请求 |
@/utils/request;列表 AjaxResult.data 为 items[] + checkedSummary |
| 鉴权 |
全部 /api/cart/** 须会员 Token |
| 页面位置 |
主包 Tab pages/cart/index(与 pages.json tabBar 一致) |
| 规格 v1 |
统一规格;加购 specKey 不传,specText 由详情拼接或「默认」 |
| 防抖 |
改量/勾选/去结算使用 useActionGuard |
| 参考 |
subpackage/order/checkout-cart.vue(去结算下游)、pages/mine 未登录态 |
2. 页面与路由
| 页面 |
需求代号 |
路径 |
入口 |
| 购物车列表 |
A |
pages/cart/index |
底部 Tab「购物车」;详情加购后可自行切 Tab |
| 确认订单(多商品) |
— |
subpackage/order/checkout-cart |
本页 去结算(另册维护) |
未登录: 空态 +「去登录」→ PAGE_LOGIN(CT0)
路径常量:
| 常量 |
路径 |
PAGE_CART |
/pages/cart/index |
PAGE_CHECKOUT_CART |
/subpackage/order/checkout-cart |
预加载: pages.json → preloadRule 为 pages/cart/index 预加载 pkg-order。
3. 文件清单
| 类型 |
路径 |
说明 |
| Tab 页 |
shop-app/pages/cart/index.vue |
分组列表、工具栏、底栏全选/合计/去结算 |
| 店组 |
shop-app/components/cart/CartShopGroup.vue |
店头全选、进店、休息中标签 |
| 商品行 |
shop-app/components/cart/CartItemRow.vue |
勾选、数量、小计、失效标签、删除、进详情 |
| 购物车 API |
shop-app/api/cart.js |
/api/cart/** |
| 展示 |
shop-app/utils/cartDisplay.js |
扁平 items 按店分组、失效文案、勾选统计 |
| 结算导航 |
shop-app/utils/checkoutNav.js |
goCartCheckout(cartItemIds) |
| 规格展示 |
shop-app/utils/cartSpec.js |
parseCartSpecText(§ 分隔) |
| 常量 |
shop-app/constants/cart.js |
失效类型、空态、跨店提示 |
| 常量 |
shop-app/constants/checkout.js |
CART_CHECKOUT_IDS_KEY |
已改上游:
| 文件 |
改动 |
subpackage/goods/detail.vue |
doAddCart → POST /api/cart/items |
4. 接口封装(api/cart.js)
基路径: /api/cart
| 方法 |
HTTP |
路径 |
场景 |
getCartList |
GET |
/api/cart |
Tab onShow 拉列表 |
addCartItem |
POST |
/api/cart/items |
详情加购 |
updateCartQuantity |
PUT |
/api/cart/items/{id}/quantity |
+/- 改量 |
updateCartChecked |
PUT |
/api/cart/items/checked |
行/店/全选 |
removeCartItem |
DELETE |
/api/cart/items/{id} |
单行删除 |
removeCartItems |
DELETE |
/api/cart/items |
删除选中 |
cleanInvalidCart |
DELETE |
/api/cart/invalid |
清理失效 |
prepareCartCheckout |
POST |
/api/cart/checkout/prepare |
去结算门禁 |
4.1 列表响应 CartListVO
| 字段 |
说明 |
items[] |
扁平购物车行(含 shopId/shopName/shopStatus);排序 cart_item_id DESC |
checkedSummary |
已勾选且 purchasable 行合计 |
前端 mapCartList 将 items[] 按 shopId 分组 为 UI 用 groups[](后端不分组)。
4.2 加购 Body(详情)
| 字段 |
说明 |
| goodsId |
必填 |
| quantity |
必填 |
| specText |
规格快照;无则「默认」 |
4.3 批量勾选 Body
{
"items": [
{ "cartItemId": 1, "checked": true }
]
}
4.4 去结算 Body
{ "cartItemIds": [1, 2] }
成功后再跳转确认订单页;不在购物车页缓存 prepare 结果(确认页走 POST /api/checkout/preview)。
5. 列表页结构(pages/cart/index.vue)
购物车 Tab
├── 未登录:空态 + 去登录
├── 加载中 / 加载失败(重试)
├── 空购物车:「购物车是空的」+ 去逛逛(首页 Tab)
└── 有数据
├── 顶栏工具条
│ ├── 清理失效商品(有失效行时显示)
│ └── 删除选中(有勾选时显示)
├── scroll-view · CartShopGroup × N
└── 底栏
├── 全选(仅可购行)
├── 合计 ¥checkedSummary.checkedAmountText
└── 去结算(N)
6. 列表页逻辑
onShow
→ 无 Token:访客空态
→ 有 Token:GET /api/cart → mapCartList(items 按店分组)
店组头勾选
→ 该店全部 purchasable 行 checked 同步 → PUT checked → 刷新
行勾选 / 底栏全选
→ PUT checked → 刷新(含 checkedSummary)
数量 +/-
→ PUT quantity → 刷新(库存不足后端 400)
删除单行
→ 二次确认 → DELETE 单行 → 刷新
删除选中
→ 二次确认(展示件数)→ DELETE 批量 → 刷新
清理失效
→ countInvalidCartItems → 二次确认(展示件数)→ DELETE /invalid → Toast removedCount
去结算
→ 无勾选可购行:提示
→ 跨店勾选:Toast「请选择同一店铺的商品结算」
→ POST prepare 成功 → goCartCheckout(ids)
→ prepare 失败:request 已 Toast,不跳转
| 需求规则 |
实现 |
| CT2 按店分组 |
groupCartItemsByShop |
| 失效不可勾选 |
purchasable=false 置灰勾选 |
| CT-S1 不跨店结算 |
getCheckedShopIds.size > 1 拦截 |
| CT7 清理失效 |
顶栏按钮 + 件数确认 |
| 缺货/下架进详情 |
点击主图/名称 goGoodsDetail |
| 进店 |
点击店名 goShopHome |
| 行小计 |
subtotalText 展示 |
6.1 底栏合计
使用接口 checkedSummary(仅 已勾选且可购 行),与后端口径一致。
6.2 失效标签
invalidType → getCartInvalidLabel(cartDisplay.js):
| invalidType |
默认文案 |
| OUT_OF_STOCK |
缺货 |
| OFF_SHELF |
已下架 |
| SHOP_CLOSED |
休息中 |
| CATEGORY_HIDDEN |
不可购买 |
| GOODS_DELETED |
已失效 |
| SHOP_DELETED |
店铺失效 |
优先使用后端 invalidMsg。
7. 组件说明
7.1 CartShopGroup.vue
- 店头:勾选(仅当有可购行)、店名、停业「休息中」、进店箭头
- 子组件
CartItemRow 列表
7.2 CartItemRow.vue
- 可购:勾选、+/- 改量、删除
- 失效:勾选禁用、数量只读、失效标签、仍可删、可点进详情
- 展示:主图、名称、规格列表、单价、小计
8. 数据映射(cartDisplay.js)
| 函数 |
用途 |
mapCartList |
items[] → groups[] + checkedSummary |
groupCartItemsByShop |
内部:按 shopId 分组,保持行序 |
hasInvalidCartItems |
是否显示「清理失效」 |
countInvalidCartItems |
清理前展示件数 |
getCheckedPurchasableIds |
去结算 / prepare 入参 |
getCheckedShopIds |
跨店校验 |
getAllPurchasableItems |
全选逻辑 |
getCartInvalidLabel |
失效标签文案 |
行模型要点: displayPic、priceText、subtotalText、specList、invalidLabel、purchasable
9. 与确认订单(多商品)边界
| 项 |
购物车侧 |
| prepare |
POST /api/cart/checkout/prepare 门禁(四条件、同店) |
| 跳转 |
goCartCheckout → checkout-cart?cartItemIds= + storage 兜底 |
| 预览/提交 |
不在本页;见《确认订单页(多商品)前端技术方案》 |
| 支付成功删行 |
后端 处理;返回 Tab 刷新可见 |
去结算
→ prepareCartCheckout(ids)
→ goCartCheckout(ids)
→ setStorage CART_CHECKOUT_IDS_KEY
→ navigateTo PAGE_CHECKOUT_CART
10. 联调检查清单
11. 非本期(前端不实现)
| 项 |
说明 |
| 列表/搜索快捷加购 |
仅详情加购 |
| 跨店一键多单 |
CT-S1 不支持 |
| 优惠券、凑单 |
未要求 |
| 失效自动删除 |
用户触发「清理失效」 |
12. 修订记录
| 版本 |
说明 |
| v1.1 |
对齐需求 v1.0:items 前端按店分组、清理失效件数确认、行小计、去结算跳转 checkout-cart;更新与多商品确认页边界 |
| v1.0 |
首版:Tab 购物车、详情加购、同店 prepare |
文档版本:v1.1 · 不修改《购物车技术方案.md》(后端方案)。