mirror of
https://github.com/crmeb/CRMEB.git
synced 2026-10-28 13:31:04 +00:00
fix(预售加购): 预售/自定义表单商品隐藏加购并拦截加入购物车
列表补齐 cart_button,详情从 SKU 回填最小有效会员价供展示。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
300b1d8677
commit
e87a6b20be
@ -339,6 +339,10 @@ class StoreCartServices extends BaseService
|
||||
if (!$new && $this->isDirectCartMode($product_id)) {
|
||||
throw new ApiException('该商品不支持加入购物车,请直接购买');
|
||||
}
|
||||
// 预售商品走预售下单流程,禁止加入购物车(立即购买 new=true 不受限)
|
||||
if (!$new && $this->isPresaleProduct($product_id)) {
|
||||
throw new ApiException('预售商品不支持加入购物车,请直接购买');
|
||||
}
|
||||
if ($type == 0) {
|
||||
//检查限购
|
||||
$this->checkLimit($uid, $product_id, $cart_num, $new);
|
||||
@ -453,6 +457,20 @@ class StoreCartServices extends BaseService
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否为预售商品(开启预售后只能走预售购买,不能进购物车)
|
||||
* @param int $productId 商品ID
|
||||
* @return bool
|
||||
*/
|
||||
protected function isPresaleProduct(int $productId): bool
|
||||
{
|
||||
try {
|
||||
return (int)app()->make(CenterProductServices::class)->value(['id' => $productId], 'presale') === 1;
|
||||
} catch (\Throwable $e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**移除购物车商品
|
||||
* @param int $uid
|
||||
* @param array $ids
|
||||
@ -612,6 +630,10 @@ class StoreCartServices extends BaseService
|
||||
if (!$productServices->isValidProduct((int)$productId, 'id')) {
|
||||
throw new ApiException('该商品已下架或删除');
|
||||
}
|
||||
// 列表加购入口:预售商品禁止写入购物车
|
||||
if ($this->isPresaleProduct((int)$productId)) {
|
||||
throw new ApiException('预售商品不支持加入购物车,请直接购买');
|
||||
}
|
||||
|
||||
// 通过 ProductTypeHandler 获取默认 SKU 并校验有效性
|
||||
$skuInfo = $this->getProductSkuInfo((int)$productId, $unique);
|
||||
|
||||
@ -780,6 +780,19 @@ class CenterProductServices extends BaseService
|
||||
$svipOpen = $memberCardService->isOpenMemberCard('vip_price');
|
||||
} catch (\Throwable $e) {}
|
||||
$svipPriceOpen = (int)sys_config('member_price_status');
|
||||
// 商品主表 vip_price 可能为 0(会员价只写在 SKU),从规格中取最小有效会员价供详情展示
|
||||
if ((float)($storeInfo['vip_price'] ?? 0) <= 0 && !empty($productValue)) {
|
||||
$skuVipPrices = [];
|
||||
foreach ($productValue as $skuRow) {
|
||||
$skuVip = (float)($skuRow['vip_price'] ?? 0);
|
||||
if ($skuVip > 0) {
|
||||
$skuVipPrices[] = $skuVip;
|
||||
}
|
||||
}
|
||||
if ($skuVipPrices) {
|
||||
$storeInfo['vip_price'] = (string)min($skuVipPrices);
|
||||
}
|
||||
}
|
||||
$storeInfo['svip_economize_price'] = bcsub((string)$storeInfo['price'], (string)$storeInfo['vip_price'], 2);
|
||||
if (!($svipOpen && sys_config('member_card_status') && $storeInfo['is_vip'] && sys_config('member_price_status', 1))) {
|
||||
$storeInfo['vip_price'] = 0;
|
||||
@ -931,9 +944,8 @@ class CenterProductServices extends BaseService
|
||||
$storeInfo['cart_strategy']['cart_mode'] = 'direct';
|
||||
}
|
||||
|
||||
// cart_button 由 cart_strategy.cart_mode 决定:direct 模式不展示加入购物车按钮
|
||||
// 预售商品在模板中走独立分支,不影响此处判断
|
||||
$storeInfo['cart_button'] = ($storeInfo['cart_strategy']['cart_mode'] ?? 'cart') === 'direct' ? 0 : 1;
|
||||
// 预售 / 自定义表单 / direct 模式均不展示加入购物车
|
||||
$storeInfo['cart_button'] = $this->canShowCartButton($storeInfo) ? 1 : 0;
|
||||
|
||||
// ========== 14. 组装扁平返回数据 ==========
|
||||
$result = [
|
||||
@ -1088,9 +1100,12 @@ class CenterProductServices extends BaseService
|
||||
'bottom_bar' => [
|
||||
'text' => '立即购买',
|
||||
'action' => 'submitOrder',
|
||||
// cart_button 由 cart_strategy.cart_mode 决定:direct 模式不展示加入购物车按钮
|
||||
// 自定义表单商品需填表后直接下单,同样不展示加入购物车
|
||||
'extra' => ['cart_button' => !$this->hasCustomForm($extensions['custom_form'] ?? []) && $this->getCartModeByType($productType) !== 'direct'],
|
||||
// 预售 / 自定义表单 / direct 模式均不展示加入购物车
|
||||
'extra' => ['cart_button' => $this->canShowCartButton([
|
||||
'presale' => $data['product']['presale'] ?? 0,
|
||||
'custom_form' => $extensions['custom_form'] ?? [],
|
||||
'product_type' => $productType,
|
||||
])],
|
||||
],
|
||||
'submit_api' => 'center/order/create',
|
||||
];
|
||||
@ -1595,6 +1610,26 @@ class CenterProductServices extends BaseService
|
||||
return trim((string)$customForm) !== '';
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否允许展示/使用加入购物车
|
||||
* 预售、自定义表单、direct 加购模式均不允许进购物车,应进详情直接购买
|
||||
* @param array $item 商品信息(需含 presale / custom_form / product_type)
|
||||
* @return bool
|
||||
*/
|
||||
protected function canShowCartButton(array $item): bool
|
||||
{
|
||||
if ((int)($item['presale'] ?? 0) === 1) {
|
||||
return false;
|
||||
}
|
||||
if ($this->hasCustomForm($item['custom_form'] ?? '')) {
|
||||
return false;
|
||||
}
|
||||
if ($this->getCartModeByType((string)($item['product_type'] ?? 'normal')) === 'direct') {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取产品类型展示名称
|
||||
* 通过 ProductTypeRegistry 咨询对应 Handler
|
||||
@ -2458,8 +2493,8 @@ class CenterProductServices extends BaseService
|
||||
if (!$this->vipIsOpen(!!$item['is_vip'], $vipStatus)) {
|
||||
$item['vip_price'] = 0;
|
||||
}
|
||||
// 自定义表单商品不支持加入购物车(前端据此点击直接进详情)
|
||||
$item['cart_button'] = $this->hasCustomForm($item['custom_form'] ?? '') || $this->getCartModeByType($item['product_type'] ?? 'normal') === 'direct' ? 0 : 1;
|
||||
// 预售 / 自定义表单 / direct 模式不支持加入购物车(前端据此进详情)
|
||||
$item['cart_button'] = $this->canShowCartButton($item) ? 1 : 0;
|
||||
if (count($item['star'])) {
|
||||
$item['star'] = bcdiv((string)array_sum(array_column($item['star'], 'product_score')), (string)count($item['star']), 1);
|
||||
} else {
|
||||
@ -2641,10 +2676,13 @@ class CenterProductServices extends BaseService
|
||||
if (!array_key_exists('vip_user', $where)) {
|
||||
$where['vip_user'] = $this->resolveVipUserLevel($uid);
|
||||
}
|
||||
$list = $this->dao->getSearchList($where, $page, $limit, ['id,name as store_name,cate_id,image,IFNULL(sales, 0) + IFNULL(virtual_sales, 0) as sales,price,stock,unit_name,presale,is_vip,vip_price']);
|
||||
$list = $this->dao->getSearchList($where, $page, $limit, ['id,name as store_name,cate_id,image,IFNULL(sales, 0) + IFNULL(virtual_sales, 0) as sales,price,stock,unit_name,presale,custom_form,product_type,is_vip,vip_price']);
|
||||
// eb_product_center 无 activity 列,补默认值兼容 getActivityList
|
||||
foreach ($list as &$item) {
|
||||
$item['activity'] = $item['activity'] ?? '';
|
||||
$item['presale'] = (int)($item['presale'] ?? 0);
|
||||
// 预售 / 自定义表单 / direct 模式不支持加入购物车
|
||||
$item['cart_button'] = $this->canShowCartButton($item) ? 1 : 0;
|
||||
}
|
||||
$list = $this->getActivityList($list);
|
||||
return $list;
|
||||
@ -2742,9 +2780,8 @@ class CenterProductServices extends BaseService
|
||||
}
|
||||
$storeInfo['cart_strategy'] = $cartStrategy;
|
||||
|
||||
// cart_button 由 cart_strategy.cart_mode 决定:direct 模式不展示加入购物车按钮
|
||||
// 预售商品在模板中走独立分支,不影响此处判断
|
||||
$storeInfo['cart_button'] = ($cartStrategy['cart_mode'] ?? 'cart') === 'direct' ? 0 : 1;
|
||||
// 预售 / 自定义表单 / direct 模式均不展示加入购物车
|
||||
$storeInfo['cart_button'] = $this->canShowCartButton($storeInfo) ? 1 : 0;
|
||||
|
||||
$specs = $handler->getDetailSpecs($id);
|
||||
$productAttr = $specs['productAttr'] ?? [];
|
||||
@ -3988,6 +4025,7 @@ class CenterProductServices extends BaseService
|
||||
'is_vip',
|
||||
'vip_price',
|
||||
'custom_form',
|
||||
'presale',
|
||||
];
|
||||
|
||||
$list = $this->dao->getSearchList($where, $page, $limit, $field);
|
||||
@ -3997,13 +4035,13 @@ class CenterProductServices extends BaseService
|
||||
$item['activity'] = '';
|
||||
$item['vip_price'] = '0.00';
|
||||
$item['is_virtual'] = $this->isVirtualProduct($item['product_type'] ?? 'normal');
|
||||
$item['presale'] = 0;
|
||||
$item['presale'] = (int)($item['presale'] ?? 0);
|
||||
$item['min_qty'] = 1;
|
||||
$item['label_list'] = '';
|
||||
$item['store_info'] = '';
|
||||
$item['star'] = '5.0';
|
||||
// 自定义表单商品不支持加入购物车(前端据此点击直接进详情)
|
||||
$item['cart_button'] = $this->hasCustomForm($item['custom_form'] ?? '') || $this->getCartModeByType($item['product_type'] ?? 'normal') === 'direct' ? 0 : 1;
|
||||
// 预售 / 自定义表单 / direct 模式不支持加入购物车(前端据此进详情)
|
||||
$item['cart_button'] = $this->canShowCartButton($item) ? 1 : 0;
|
||||
|
||||
// 标记活动商品
|
||||
if (!empty($item['activity'])) {
|
||||
|
||||
@ -23,12 +23,15 @@
|
||||
</view>
|
||||
<view class="flex-between-center mt-12">
|
||||
<text class="fs-22 text--w111-999">{{ $t(`已售`) }}{{item.sales}}{{item.unit_name}}</text>
|
||||
<view class="w-44 h-44 rd-24 bg-gradient flex-center" v-if="goDetail=='goDetail'">
|
||||
<text class="iconfont icon-ic_ShoppingCart1 text--w111-fff fs-26"></text>
|
||||
</view>
|
||||
<view class="w-44 h-44 rd-24 bg-gradient flex-center" @tap.stop="addCartChange" v-else>
|
||||
<text class="iconfont icon-ic_ShoppingCart1 text--w111-fff fs-26"></text>
|
||||
</view>
|
||||
<!-- 预售等 cart_button=0 的商品列表不展示加购入口 -->
|
||||
<template v-if="item.cart_button != 0">
|
||||
<view class="w-44 h-44 rd-24 bg-gradient flex-center" v-if="goDetail=='goDetail'">
|
||||
<text class="iconfont icon-ic_ShoppingCart1 text--w111-fff fs-26"></text>
|
||||
</view>
|
||||
<view class="w-44 h-44 rd-24 bg-gradient flex-center" @tap.stop="addCartChange" v-else>
|
||||
<text class="iconfont icon-ic_ShoppingCart1 text--w111-fff fs-26"></text>
|
||||
</view>
|
||||
</template>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
@ -1570,8 +1570,6 @@ function ChangeCartNum(changeValue, num, stock, isDuo, id, index, cart) {
|
||||
if (!isDuo) {
|
||||
if (cart) {
|
||||
goCat(0, id, 1, 1, num.product_attr_unique);
|
||||
// 遗留 bug:原 mixin 调用 this.getTotalPrice(),本组件从未定义该方法(运行时必报错),保持原语义
|
||||
getTotalPrice();
|
||||
} else {
|
||||
goCat(0, id, 1);
|
||||
}
|
||||
@ -1599,7 +1597,6 @@ function ChangeCartNum(changeValue, num, stock, isDuo, id, index, cart) {
|
||||
if (!isDuo) {
|
||||
if (cart) {
|
||||
goCat(0, id, 0, 1, num.product_attr_unique);
|
||||
getTotalPrice();
|
||||
} else {
|
||||
goCat(0, id, 0);
|
||||
}
|
||||
@ -1653,18 +1650,15 @@ function goCat(duo, goodsId, type, cart, unique) {
|
||||
}
|
||||
|
||||
util.Tips({
|
||||
title: res.msg
|
||||
title: res.msg || '加入购物车成功'
|
||||
});
|
||||
|
||||
getCartNum();
|
||||
if (!cart) {
|
||||
// 遗留 bug:原 mixin 调用 this.getCartList(1),本组件从未定义该方法(运行时必报错),保持原语义
|
||||
getCartList(1);
|
||||
}
|
||||
// DIY 商品列表无分类页悬浮购物车,不调用 getCartList
|
||||
})
|
||||
.catch(err => {
|
||||
return util.Tips({
|
||||
title: err
|
||||
title: (err && (err.msg || err.message)) || err
|
||||
});
|
||||
});
|
||||
}
|
||||
@ -1672,20 +1666,15 @@ function goCartDuo(item, num) {
|
||||
if (!isLogin.value) {
|
||||
toLogin();
|
||||
} else {
|
||||
if(item.cart_button == 0){
|
||||
if(item.is_presale_product){
|
||||
uni.navigateTo({
|
||||
url: `/pages/activity/goods_details/index?id=${item.id}&type=6`
|
||||
})
|
||||
}else{
|
||||
//num:表示从首页点击进来的
|
||||
let page1 = `/pages/goods_details/index?id=${item.id}&fromType=1`;
|
||||
let page2 = `/pages/goods_details/index?id=${item.id}`;
|
||||
uni.navigateTo({
|
||||
url: num?page2:page1
|
||||
})
|
||||
}
|
||||
}else{
|
||||
// 预售 / 自定义表单 / direct 模式:列表不支持加购,进详情购买
|
||||
if (item.cart_button == 0) {
|
||||
//num:表示从首页点击进来的
|
||||
let page1 = `/pages/goods_details/index?id=${item.id}&fromType=1`;
|
||||
let page2 = `/pages/goods_details/index?id=${item.id}`;
|
||||
uni.navigateTo({
|
||||
url: num ? page2 : page1
|
||||
});
|
||||
} else {
|
||||
storeName.value = item.store_name;
|
||||
getAttrs(item.id);
|
||||
id.value = item.id;
|
||||
@ -1698,17 +1687,12 @@ function goCartDan(item, index, num) {
|
||||
if (!isLogin.value) {
|
||||
toLogin();
|
||||
} else {
|
||||
if(item.cart_button == 0){
|
||||
if(item.is_presale_product){
|
||||
uni.navigateTo({
|
||||
url: `/pages/activity/goods_details/index?id=${item.id}&type=6`
|
||||
})
|
||||
}else{
|
||||
uni.navigateTo({
|
||||
url: `/pages/goods_details/index?id=${item.id}&fromType=1`
|
||||
})
|
||||
}
|
||||
}else{
|
||||
// 预售 / 自定义表单 / direct 模式:列表不支持加购,进详情购买
|
||||
if (item.cart_button == 0) {
|
||||
uni.navigateTo({
|
||||
url: `/pages/goods_details/index?id=${item.id}&fromType=1`
|
||||
});
|
||||
} else {
|
||||
tempArr.value[index].cart_num = 1;
|
||||
// num表示从门店过来的;
|
||||
// if(num){
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user