name: 商城购物车结算优化 overview: 让 mallApp 花束商品也能加入购物车并与花材共用同一购物车体系,店铺首页商品加购按钮按"单规格/多规格/团购"分流交互,新建花束+花材混合结算页,并新增专用的合并下单接口而不破坏现有 order/buy-item 与 order/create-order。 todos:
selectInfo['cg'](mallApp/src/store/modules/product.js),用 property 字段区分(0=花束,1=花材),与后端 createHdOrder 及 hdPad 混合收银台的既有语义保持一致。specEnabled 字段,前端列表页直接读取该字段判断,无需先请求详情。order/create-mix-order,内部复用 \bizHd\order\services\OrderService::createHdOrder;原有 order/buy-item、order/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
groupGoodsBaseInfo()(508-554行,供 /category/goods-list 等列表接口使用):批量查询 masterId in (goodsIds) 存在即为多规格,补充 $val['specEnabled'],避免逐条 N+1 查询。formatGoodsRows()(618-635行,供首页热销/上新/拼团等模块使用):同样批量补充 specEnabled。GoodsClass 新增一个共用的静态方法(如 getSpecEnabledMap($goodsIds))供两处调用,避免重复实现。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 组合键。将:
<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) 跳转逻辑。
add-btn(21行)与 cart-icon(39行)当前都绑定/冒泡到 goDetail(g),改为各自绑定 @click.stop="handleCartClick(g)"。handleCartClick(g) 按 g.specEnabled 分流:单规格 → 直接加购 + toast;多规格 → goDetail(g)。当前 mallApp/src/pages/goods/detail.vue 只有"购买"按钮(buy-foot.vue)→ 弹出 sel-popup.vue 选规格 → "下一步"直接进入 order/buy 单品直购,没有加入购物车的出口。需新增:
buy-foot.vue:新增"加入购物车"按钮,emit('cart')。sel-popup.vue:区分触发来源(购物车 or 立即购买),新增一个"加入购物车"按钮,选完规格后写入 selectList(property:0 + specGoodsId)并关闭弹窗、toast提示,不跳转 order/buy;原"下一步"立即购买逻辑不变。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。mallApp/src/pages/billing/affirmMix.vueHbSelect 红包、TuiListCell、mx-datepicker、底部合计+提交栏),商品清单按 property 分组展示花材与花束两部分,分别计价再汇总。app-delivery 组件。createMixOrder。pages.json 的 billing 分组下注册新路由。新增:
export const createMixOrder = data => {
return https.post('/order/create-mix-order', data)
}
新增 actionCreateMixOrder,设计要点:
actionBuyItem(201-562行)与 actionCreateOrder(565-904行),两者保持现状供各自原有页面使用。product[] 允许同时包含 property:0(花束,可带 specGoodsId)与 property:1(花材,带 itemId/unitType)的条目。actionBuyItem 中的定价(\bizGhs\product\classes\ProductClass::getFinalPrice)、限购(handleLimitBuy)、预售校验逻辑。actionCreateOrder 中的规格解析(specGoodsId → GoodsClass)、定价(\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)。实现阶段需要重点核实/决策的风险点(已知但需要写代码时具体验证,不影响本次方案定型):
actionBuyItem 通过 hdId → HdClass → hd.customId → CustomClass 取 $custom;actionCreateOrder 直接用 $this->custom。需确认在 mallApp 场景下两者解析结果是否一致,合并接口取哪个作为准。goodsType:1,花束下单时 goodsType:0,混合单如何统一计价(分别计价再相加,还是 DeliveryQuoteUtil 需要支持混合 goodsType)需要在实现时与 DeliveryQuoteUtil 逻辑确认。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.php(groupGoodsBaseInfo 补 specEnabled)biz-hd/homePageConfig/classes/HomePageModuleClass.php(formatGoodsRows 补 specEnabled)app-mall/controllers/OrderController.php(新增 actionCreateMixOrder)