文档目录
购物车页面模块

简介

本模块面向 DouPHP 小程序的“购物车”页面,覆盖商品添加、数量修改、删除、角标同步、库存校验、价格计算(含属性差价与会员价)、以及结算前的库存锁定等关键能力。文档从前端到后端逐层说明数据流、业务规则与异常处理,并提供可操作的 API 调用示例与常见问题解决方案。

项目结构

购物车在小程序端由 Store 管理角标与数量,页面负责交互与数据加载;后端通过声明式路由将 /order/cart/* 映射到 CartController,再委托给 CartService 完成加购/改数/删除,使用 OrderCartQuery 组装购物车视图,OrderStockGuard 负责库存校验与实时可售库存计算。

graph TB
subgraph "小程序"
A["stores/cart.ts<br/>角标与数量"]
B["pages/order/order.ts<br/>购物车页面"]
end
subgraph "API 网关"
R["api/route/order.php<br/>路由映射"]
end
subgraph "控制器与服务"
C["api/controller/order/CartController.php<br/>增/改/删/数量"]
S["front/service/order/CartService.php<br/>加购/改数/删除"]
Q["core/service/order/OrderCartQuery.php<br/>购物车读模型"]
K["core/service/order/OrderStockGuard.php<br/>库存校验"]
O["core/service/order/OrderService.php<br/>统一入口"]
end
A --> B
B --> R
R --> C
C --> S
S --> Q
S --> K
S --> O

核心组件

  • 小程序 Store:维护购物车数量与角标文案,支持可选模块降级与未登录兜底。
  • 购物车页面:鉴权后拉取购物车数据,提供数量增减、滑动删除等交互。
  • 路由与控制器:声明式路由将 order/cart 相关请求分发至 CartController。
  • 购物车服务:实现加购、改数、删除,并联动库存校验与价格计算。
  • 购物车读模型:按用户聚合购物车项,计算小计、总价、积分等汇总字段。
  • 库存守卫:下单前回收过期订单占用库存,计算实时可售库存并校验。
  • 统一入口:OrderService 暴露 getCart/checkStock 等方法供上层调用。

架构总览

购物车流程分为“读”和“写”两条主线:

  • 读:小程序页面请求 order 接口获取购物车视图数据,后端通过 OrderCartQuery 聚合商品、属性、价格、积分与合计信息返回。
  • 写:小程序触发加购/改数/删除,CartController 接收参数并交由 CartService 执行,期间进行商品存在性、规格属性合法性、库存校验与写入数据库。
sequenceDiagram
participant U as "小程序页面"
participant S as "stores/cart.ts"
participant P as "pages/order/order.ts"
participant R as "api/route/order.php"
participant C as "CartController"
participant SV as "CartService"
participant Q as "OrderCartQuery"
participant K as "OrderStockGuard"
U->>P : 进入购物车页
P->>R : GET /order
R->>C : 路由到 index
C->>Q : getCart(user_id)
Q-->>C : 购物车视图
C-->>P : {title, cart}
P-->>U : 渲染列表/合计
U->>S : 刷新角标
S->>R : GET /order/cart/cart_number
R->>C : cartNumber()
C-->>S : {cart_number}
S-->>U : 更新角标
U->>P : 点击加减/删除
P->>R : PUT/DELETE /order/cart/{id}
R->>C : update/destroy
C->>SV : updateCartItem/deleteCartItem
SV->>K : checkStock(...)
K-->>SV : 校验结果
SV-->>C : 成功/错误
C-->>P : 响应
P-->>U : 刷新列表/提示

详细组件分析

小程序购物车 Store(角标与数量)

  • 功能要点
    • 根据 features.order 开关决定是否请求后端,未开启时 number 恒为 0。
    • 未登录或后端异常时静默返回 0,避免阻断 UI。
    • 角标文案:0 显示空串,>99 显示“99+”。
  • 数据流
    • refresh() 内部先判断模块开关与登录态,再调用 http.get('order/cart/cart_number') 获取 cart_number。
    • 使用 runInAction 安全更新 observable 状态。
flowchart TD
Start(["refresh()"]) --> CheckModule{"features.order === true ?"}
CheckModule --> |否| SetZero["number=0"] --> End
CheckModule --> |是| CheckLogin{"有 api_token ?"}
CheckLogin --> |否| SetZero2["number=0"] --> End
CheckLogin --> |是| Fetch["GET /order/cart/cart_number"]
Fetch --> Update["runInAction(number = cart_number)"] --> End(["结束"])

购物车页面(交互与数据加载)

  • 功能要点
    • onShow/onLoad 中绑定 commonStore,设置购买模式。
    • loadData() 调用 GET /order 获取 title 与 cart 列表。
    • changeNumber() 调用 PUT /order/cart/{id},携带 action(plus/minus/input)。
    • touchStart/touchMove/touchEnd 实现侧滑展示删除按钮。
    • itemDel() 调用 DELETE /order/cart/{id} 删除条目。
  • 错误处理
    • 网络或业务错误统一通过 douMsg 提示。
sequenceDiagram
participant P as "pages/order/order.ts"
participant R as "api/route/order.php"
participant C as "CartController"
participant SV as "CartService"
P->>R : GET /order
R->>C : index()
C-->>P : {title, cart}
P-->>P : setData({title, cart})
P->>R : PUT /order/cart/{id}?action=plus|minus|input
R->>C : update()
C->>SV : updateCartItem(userId, id, number)
SV-->>C : {subtotal, total, item_number, item_amount}
C-->>P : success
P-->>P : loadData() 刷新
P->>R : DELETE /order/cart/{id}
R->>C : destroy()
C->>SV : deleteCartItem(userId, id)
C-->>P : success
P-->>P : loadData() 刷新

后端购物车控制器与服务

  • 控制器职责
    • 路由映射:/order/cart 子资源 store/update/destroy,以及根级 cart_number。
    • 参数规范化:store 支持 JSON 字符串 post 兼容;update 解析 action 计算目标数量。
    • 登录校验:mustLoginUserId() 未登录抛 401。
  • 服务职责
    • addToCart:校验商品存在、规格属性合法、库存充足;跨模块或积分兑换清空购物车;非普通商品或立即购买则清空购物车。
    • updateCartItem:仅 product 且非一键购买时允许;更新数量前再次校验库存,若不足则回退到实时可售库存;重新计算小计与总额。
    • deleteCartItem:按 user_id 与 id 删除。
classDiagram
class CartController {
+cartNumber()
+store(request)
+update(request)
+destroy(request)
}
class CartService {
+addToCart(userId,module,itemId,number,mode,action,attParams)
+updateCartItem(userId,cartId,number)
+deleteCartItem(userId,cartId)
}
class OrderCartQuery {
+getCart(user_id)
+clearCart(user_id)
}
class OrderStockGuard {
+checkStock(module,item_id,number)
+realTimeStock(module,item_id)
}
CartController --> CartService : "委托"
CartService --> OrderCartQuery : "读取购物车"
CartService --> OrderStockGuard : "校验库存"

购物车读模型与价格计算

  • 读模型职责
    • 按 user_id 拉取 order_cart,批量查询商品基础信息。
    • 装配购物车项:名称、图片、原价/售价、属性名与差价、积分换算、小计与总计。
    • 清理无效项:当关联商品不存在时自动删除该购物车项。
  • 价格计算逻辑
    • 最终单价优先采用 salePrice(会员/促销价),否则使用 base_price + attribute price_change。
    • 小计 = 最终单价 × 数量;价格为 0 时显示“面议”。
    • 累计 total、item_amount、order_point。
flowchart TD
A["getCart(user_id)"] --> B["读取 order_cart 列表"]
B --> C{"是否有数据?"}
C --> |否| E["返回 false"]
C --> |是| D["批量查询商品/属性/价格"]
D --> F["buildCartItem: 计算最终单价/小计"]
F --> G["累加 total/item_amount/order_point"]
G --> H["返回购物车视图"]

库存校验与防超卖

  • 校验时机
    • 加入购物车时:检查 stock 是否足够。
    • 修改数量时:若不足,回退到实时可售库存。
    • 结算下单前:再次校验并锁定库存(stock_lock=1)。
  • 实时可售库存
    • realTimeStock = 商品 stock - 已锁定但未付款的订单数量之和。
    • 校验前先触发过期订单回收,释放被占用的库存。
  • 防超卖策略
    • 以“stock - 锁定中数量”作为可售库存,避免并发超卖。
    • 下单链路对每个商品逐项校验,任一不满足即失败。
flowchart TD
Start(["checkStock(module,item_id,number)"]) --> Pre["autoCancelOrder() 回收过期订单"]
Pre --> HasStock{"表含 stock 字段?"}
HasStock --> |否| OK["without_limit"]
HasStock --> |是| RTS["realTimeStock = stock - 锁定中数量"]
RTS --> Enough{"number <= real_time_stock ?"}
Enough --> |是| OK
Enough --> |否| Out["out_stock(返回 real_time_stock)"]

依赖关系分析

  • 小程序 Store 依赖 http 与 route 工具,受 commonStore.features.order 控制。
  • 页面依赖 authStore.ensureLogin 保证登录后操作。
  • 路由将 /order/cart/* 映射到 CartController,控制器依赖 CartService。
  • CartService 依赖 OrderCartQuery(读)与 OrderStockGuard(写前校验),并通过 OrderService 暴露统一方法。
  • 结算阶段 CheckoutService 会再次校验库存,确保下单前数据一致。
graph LR
Store["stores/cart.ts"] --> Page["pages/order/order.ts"]
Page --> Route["api/route/order.php"]
Route --> Ctrl["CartController"]
Ctrl --> Svc["CartService"]
Svc --> Read["OrderCartQuery"]
Svc --> Stock["OrderStockGuard"]
Svc --> Core["OrderService"]

性能与一致性

  • 读优化
    • 批量查询商品与属性,减少 N+1 查询。
    • 购物车视图聚合计算一次返回,降低前端多次请求。
  • 写优化
    • 更新数量时仅在 product 模块且非一键购买模式下生效,减少不必要计算。
    • 库存校验前置,失败快速返回。
  • 一致性
    • 购物车数据持久化于数据库(order_cart),多设备通过登录态共享。
    • 结算前二次校验库存,结合 stock_lock 机制防止超卖。
    • 过期订单自动回收释放库存,保障可售库存准确性。

故障排查指南

  • 商品下架/删除
    • 现象:购物车出现无效项。
    • 处理:OrderCartQuery 在构建视图时发现商品不存在会自动删除该购物车项。
    • 建议:前端收到空列表或无对应商品时提示“商品已下架”。
  • 库存不足
    • 现象:加购或改数时报错。
    • 处理:checkStock 返回 out_stock 并附带 real_time_stock;updateCartItem 会将数量回退到实时可售库存。
    • 建议:前端提示“库存不足,已调整为可售数量”。
  • 购物车数据清理
    • 场景:跨模块切换、积分兑换、立即购买或一键购买配置开启时会清空购物车。
    • 建议:在切换模块或进入结算页前提示“购物车将被清空”,避免误操作。
  • 登录态失效
    • 现象:未登录访问购物车接口返回 401。
    • 处理:CartController.mustLoginUserId 抛出未授权;小程序需引导重新登录。
    • 建议:Store 在未登录时直接置零角标,避免无效请求。

结论

本模块通过清晰的分层设计与严格的库存校验,实现了稳定可靠的购物车体验。前端 Store 与页面解耦,后端服务聚焦业务规则,读模型高效聚合数据,库存守卫保障一致性。建议在扩展新功能时遵循现有契约:所有写操作前进行库存校验,读操作批量查询以减少开销,并在前端做好未登录、模块关闭与异常的优雅降级。

附录:API 参考与示例

  • 路由与端点
    • GET /order/cart/cart_number:获取购物车数量(未登录返回 0)。
    • POST /order/cart:添加商品到购物车。
    • PUT /order/cart/{id}:更新购物车项数量(action: plus/minus/input)。
    • DELETE /order/cart/{id}:删除购物车项。
  • 请求/响应要点
    • 添加商品:支持 module、item_id、item_number、mode(money/point)、action(addtocart/buynow),以及 att_xxx 规格参数。
    • 更新数量:action=input 时需传入 item_number;plus/minus 由服务端计算。
    • 响应:统一 ApiResponse 格式,错误包含 code/msg,成功包含必要字段(如 subtotal、total、item_number、item_amount)。
  • 小程序调用示例(概念性)
    • 获取购物车数据:http.get(route('order'))
    • 更新数量:http.put(route('order.cart.update', {id}), {action, id})
    • 删除商品:http.del(route('order.cart.destroy', {id}), {id})
    • 刷新角标:http.get(route('order.cart'))
添加日期:2026-10-05