5-购物车与结算优化.md 13 KB


name: 商城购物车结算优化 overview: 让 mallApp 花束商品也能加入购物车并与花材共用同一购物车体系,店铺首页商品加购按钮按"单规格/多规格/团购"分流交互,新建花束+花材混合结算页,并新增专用的合并下单接口而不破坏现有 order/buy-item 与 order/create-order。 todos:

  • id: backend-spec-field content: 后端列表接口(groupGoodsBaseInfo/formatGoodsRows)补充specEnabled字段 status: completed
  • id: cart-data-model content: 扩展cgProduct.js购物车行结构支持property区分花束/花材 status: completed
  • id: shop-category-cart content: shop-category.vue花束分类页加购分流(单规格直加/多规格跳转) status: completed
  • id: goods-section-cart content: goodsSection.vue首页商品卡加购按钮分流 status: completed
  • id: detail-add-cart content: goods/detail.vue+buy-foot+sel-popup补充加入购物车出口 status: in_progress
  • id: cart-page-mixed content: cart.vue支持花束/花材混合展示、去重键、结算路由分流 status: pending
  • id: affirm-mix-page content: 新建billing/affirmMix.vue合并结算页并注册路由 status: pending
  • id: api-create-mix-order content: 前端新增createMixOrder API封装 status: pending
  • id: backend-mix-order-action content: 后端新增actionCreateMixOrder,复用createHdOrder不破坏原接口 status: pending isProject: false ---

商城购物车与结算流程优化实施计划

已确认的关键设计决策

  1. 购物车数据结构:花束加入购物车后与花材共用同一个 Vuex 购物车列表 selectInfo['cg']mallApp/src/store/modules/product.js),用 property 字段区分(0=花束,1=花材),与后端 createHdOrder 及 hdPad 混合收银台的既有语义保持一致。
  2. 单规格/多规格判断:由后端在列表接口中补充 specEnabled 字段,前端列表页直接读取该字段判断,无需先请求详情。
  3. 花束分类页(1.1):也遵循 1.2 的规则——单规格直接加购,多规格跳转详情选规格,与店铺首页行为保持一致。
  4. 结算下单 API新增专用合并结算接口 order/create-mix-order,内部复用 \bizHd\order\services\OrderService::createHdOrder;原有 order/buy-itemorder/create-order 保持不变,继续服务各自原场景。

架构说明

flowchart TD
    shopCategory["shop-category.vue 花束分类"] -->|"点击购物车按钮"| checkSpec1{"specEnabled?"}
    goodsSection["goodsSection.vue 首页热销/上新"] -->|"点击 +/购物车图标"| checkSpec2{"specEnabled?"}
    checkSpec1 -->|"单规格"| addCartDirect["直接加购 property:0"]
    checkSpec1 -->|"多规格"| goDetailPage["跳转 goods/detail"]
    checkSpec2 -->|"单规格"| addCartDirect
    checkSpec2 -->|"多规格"| goDetailPage
    goDetailPage --> selPopup["sel-popup 选规格"]
    selPopup -->|"加入购物车(新增)"| addCartDirect
    selPopup -->|"立即购买(原有)"| orderBuy["pages/order/buy 单品直购"]
    activitySection["activitySection.vue 团购模块"] -->|"去开团(不变)"| goDetailPage

    addCartDirect --> selectInfoCg["Vuex selectInfo.cg\n花材(property:1) + 花束(property:0)"]
    shopCategoryItem["shop-category.vue 花材分类(已支持)"] --> selectInfoCg

    selectInfoCg --> cartPage["cart.vue 购物车"]
    cartPage -->|"勾选全部为花材"| affirmGhs["billing/affirmGhs.vue(不变)"]
    cartPage -->|"含花束(纯花束或混合)"| affirmMix["billing/affirmMix.vue(新建)"]

    affirmGhs -->|"order/buy-item(不变)"| createHdOrder["OrderService::createHdOrder"]
    orderBuy -->|"order/create-order(不变)"| createHdOrder
    affirmMix -->|"order/create-mix-order(新建)"| createHdOrder

一、购物车加入逻辑

1. 后端:列表接口补充规格标识字段(huahuibao / app-mall)

  • biz-hd/goods/classes/GoodsClass.phpgroupGoodsBaseInfo()(508-554行,供 /category/goods-list 等列表接口使用):批量查询 masterId in (goodsIds) 存在即为多规格,补充 $val['specEnabled'],避免逐条 N+1 查询。
  • biz-hd/homePageConfig/classes/HomePageModuleClass.phpformatGoodsRows()(618-635行,供首页热销/上新/拼团等模块使用):同样批量补充 specEnabled
  • 两处逻辑一致,建议在 GoodsClass 新增一个共用的静态方法(如 getSpecEnabledMap($goodsIds))供两处调用,避免重复实现。

2. 前端:购物车行支持花束(mallApp)

  • mallApp/src/mixins/cgProduct.js
    • addEvent 现有逻辑按 id+classId 判重,需要扩展为按 id+property 判重(花束行 classId 置 0,避免与花材 id 撞车)。
    • 新增花束加购方法(如 addBouquetToCart(goods, spec)),组装 { id, property:0, goodsId, specGoodsId, name, cover, price, num:1 } 写入 selectList 后复用现有 setSelectInfoByType + rememberProduct()
  • 行标识、合并/去重等所有按 id 判断唯一性的地方,统一改为 id+property 组合键。

3. 花束分类页:mallApp/src/pages/home/shop-category.vue

将:

              <view class="goods-cart-btn" @tap.stop="toBouquetDetail(item)">
                <sprite-icon name="icon-cart" :size="36" />
              </view>

改为 @tap.stop="handleAddToCart(item)",方法内按 item.specEnabled 分流:单规格直接加购并 uni.showToast({title:'已加入购物车'});多规格保留原 toBouquetDetail(item) 跳转逻辑。

4. 店铺首页:mallApp/src/components/home/goodsSection.vue

  • add-btn(21行)与 cart-icon(39行)当前都绑定/冒泡到 goDetail(g),改为各自绑定 @click.stop="handleCartClick(g)"
  • handleCartClick(g)g.specEnabled 分流:单规格 → 直接加购 + toast;多规格 → goDetail(g)
  • mallApp/src/components/home/activitySection.vue(团购/秒杀模块)无需修改:该组件本身没有购物车/加号按钮,卡片点击与"去开团"按钮已统一跳转商品详情页,天然满足"团购商品跳转团购流程"的要求。

5. 商品详情页补充"加入购物车"能力(多规格分流后的落点)

当前 mallApp/src/pages/goods/detail.vue 只有"购买"按钮(buy-foot.vue)→ 弹出 sel-popup.vue 选规格 → "下一步"直接进入 order/buy 单品直购,没有加入购物车的出口。需新增:

  • buy-foot.vue:新增"加入购物车"按钮,emit('cart')
  • sel-popup.vue:区分触发来源(购物车 or 立即购买),新增一个"加入购物车"按钮,选完规格后写入 selectListproperty:0 + specGoodsId)并关闭弹窗、toast提示,不跳转 order/buy;原"下一步"立即购买逻辑不变。

二、结算与订单创建流程优化

1. 购物车展示改造:mallApp/src/pages/home/cart.vue

  • 列表渲染区分 property===1(花材,原有 扎/支 展示)与 property===0(花束,展示"份"+规格名+单价,无 bigCount/smallCount 换算)。
  • getItemKey(370-374行)改为 `${item.id}_${item.property}_${item.classId||0}`
  • 现有按 id 做合并/去重(如 _shouldMergeSelectByProductId)的逻辑要按 property 隔离,避免花束与花材因同 id 被错误合并。
  • "去结算"(goCheckout,634-659行)按勾选项组成分流:
    • 勾选项全部为 property===1(纯花材)→ 保持跳转 /pages/billing/affirmGhs(不变,向后兼容)。
    • 勾选项包含任意 property===0(纯花束或混合)→ 跳转新页面 /pages/billing/affirmMix

2. 新建合并结算页:mallApp/src/pages/billing/affirmMix.vue

  • 参照 affirmGhs.vue 骨架搭建整体结构(地址/收货人、配送方式、HbSelect 红包、TuiListCellmx-datepicker、底部合计+提交栏),商品清单按 property 分组展示花材与花束两部分,分别计价再汇总。
  • 花束相关的跑腿收货人字段(收花人姓名/手机号)参照 order/buy.vue 及其 app-delivery 组件。
  • 提交调用新 API createMixOrder
  • pages.jsonbilling 分组下注册新路由。

3. 前端 API 封装:mallApp/src/api/order/index.js

新增:

export const createMixOrder = data => {
	return https.post('/order/create-mix-order', data)
}

4. 后端新增合并下单接口:app-mall/controllers/OrderController.php

新增 actionCreateMixOrder,设计要点:

  • 不修改 actionBuyItem(201-562行)与 actionCreateOrder(565-904行),两者保持现状供各自原有页面使用。
  • 入参 product[] 允许同时包含 property:0(花束,可带 specGoodsId)与 property:1(花材,带 itemId/unitType)的条目。
  • 花材条目:复用 actionBuyItem 中的定价(\bizGhs\product\classes\ProductClass::getFinalPrice)、限购(handleLimitBuy)、预售校验逻辑。
  • 花束条目:复用 actionCreateOrder 中的规格解析(specGoodsIdGoodsClass)、定价(\bizHd\goods\classes\GoodsClass::getFinalPrice)逻辑。
  • 两部分价格汇总后统一处理红包扣减、生成统一 modifyPrice只调用一次 \bizHd\order\services\OrderService::createHdOrder($post, $custom, $hasPay) 提交混合 product[](已验证该方法按 property 分别写 OrderGoodsClass/OrderItemClass,共用同一 orderSn,见 biz-hd/order/services/OrderService.php:28-101,125-226,299-328)。
  • 建议将两个原有 action 中可复用的定价/校验片段抽取为私有方法或 Service 方法,减少三处重复代码。

实现阶段需要重点核实/决策的风险点(已知但需要写代码时具体验证,不影响本次方案定型):

  • 客户身份解析:actionBuyItem 通过 hdId → HdClass → hd.customId → CustomClass$customactionCreateOrder 直接用 $this->custom。需确认在 mallApp 场景下两者解析结果是否一致,合并接口取哪个作为准。
  • 跑腿运费:花材下单时 goodsType:1,花束下单时 goodsType:0,混合单如何统一计价(分别计价再相加,还是 DeliveryQuoteUtil 需要支持混合 goodsType)需要在实现时与 DeliveryQuoteUtil 逻辑确认。
  • 限购/预售仅存在于花材路径,花束的规格库存扣减是独立路径,混合单中两套校验都要执行,注意事务边界与失败回滚(现有两个 action 都有 register_shutdown_function 回滚限购快照的逻辑,合并时需要保留)。

涉及文件清单汇总

前端(front-end / mallApp)

  • src/pages/home/shop-category.vue(花束分类加购分流)
  • src/components/home/goodsSection.vue(首页商品卡加购分流)
  • src/pages/goods/detail.vue / components/buy-foot.vue / components/sel-popup.vue(详情页加购出口)
  • src/mixins/cgProduct.js(购物车行结构扩展)
  • src/pages/home/cart.vue(混合展示、去重、结算路由分流)
  • src/pages/billing/affirmMix.vue(新建)
  • src/api/order/index.js(新增 createMixOrder
  • src/pages.json(注册新路由)

后端(huahuibao)

  • biz-hd/goods/classes/GoodsClass.phpgroupGoodsBaseInfospecEnabled
  • biz-hd/homePageConfig/classes/HomePageModuleClass.phpformatGoodsRowsspecEnabled
  • app-mall/controllers/OrderController.php(新增 actionCreateMixOrder