mirror of
https://github.com/crmeb/CRMEB.git
synced 2026-10-28 13:31:04 +00:00
fix(商品列表): 分类/品类券按商品 cate_id 统一筛选,并加固排序与分页参数
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
f4d4c4377b
commit
8ecd8fcbf6
@ -30,23 +30,57 @@ class CenterProductController
|
||||
*/
|
||||
public function productList(Request $request, CenterProductServices $services)
|
||||
{
|
||||
/** @var \app\services\product\product\StoreCategoryServices $categoryServices */
|
||||
$categoryServices = app()->make(\app\services\product\product\StoreCategoryServices::class);
|
||||
$where = $request->getMore([
|
||||
[['sid', 'd'], 0],
|
||||
[['cid', 'd'], 0],
|
||||
['keyword', '', '', 'store_name'],
|
||||
['priceOrder', ''],
|
||||
['salesOrder', ''],
|
||||
[['news', 'd'], 0],
|
||||
[['selectId', 'd'], 0],
|
||||
['productId', ''],
|
||||
['coupon_category_id', ''],
|
||||
['cate_id', ''],
|
||||
['limit', 30],
|
||||
['ids', ''],
|
||||
['store_label_id', ''],
|
||||
]);
|
||||
[$page, $limit] = $services->getPageValue();
|
||||
if (!empty($where['limit'])) {
|
||||
$limit = (int)$where['limit'];
|
||||
// limit 强制整型并设上限,避免异常大分页
|
||||
$limit = max(1, min(100, (int)($where['limit'] ?: $limit)));
|
||||
unset($where['limit']);
|
||||
// 排序字段白名单:只允许 asc/desc,其余清空(防 ORDER BY 注入)
|
||||
foreach (['priceOrder', 'salesOrder'] as $orderKey) {
|
||||
$orderVal = strtolower(trim((string)($where[$orderKey] ?? '')));
|
||||
$where[$orderKey] = in_array($orderVal, ['asc', 'desc'], true) ? $orderVal : '';
|
||||
if ($where[$orderKey] === '') {
|
||||
unset($where[$orderKey]);
|
||||
}
|
||||
}
|
||||
// DIY 商品列表/商品选项卡「指定商品」「商品标签」:ids/store_label_id 逗号串转数组(DAO 按数组 whereIn/FIND_IN_SET 处理,ids 需按顺序排序)
|
||||
// 分类页 selectId:有父级视为二级,否则一级
|
||||
if ($where['selectId'] && (!$where['sid'] || !$where['cid'])) {
|
||||
if ($categoryServices->value(['id' => $where['selectId']], 'pid')) {
|
||||
$where['sid'] = $where['selectId'];
|
||||
} else {
|
||||
$where['cid'] = $where['selectId'];
|
||||
}
|
||||
}
|
||||
unset($where['selectId']);
|
||||
// 品类/商品券落地页:productId → ids
|
||||
if (!empty($where['productId'])) {
|
||||
$where['ids'] = $where['productId'];
|
||||
}
|
||||
unset($where['productId']);
|
||||
// 新品排序(前端 news=1)
|
||||
if (!empty($where['news'])) {
|
||||
$where['newsOrder'] = 'news';
|
||||
}
|
||||
unset($where['news']);
|
||||
// DIY「指定商品」「商品标签」:逗号串转整型数组
|
||||
foreach (['ids', 'store_label_id'] as $idKey) {
|
||||
$idValue = is_array($where[$idKey]) ? $where[$idKey] : explode(',', (string)$where[$idKey]);
|
||||
$where[$idKey] = array_values(array_filter(array_map('intval', $idValue)));
|
||||
$where[$idKey] = toIntArray($where[$idKey] ?? '');
|
||||
if (empty($where[$idKey])) {
|
||||
unset($where[$idKey]);
|
||||
}
|
||||
@ -55,13 +89,27 @@ class CenterProductController
|
||||
// 指定商品按已选数量返回,不受默认分页条数限制
|
||||
$limit = max($limit, count($where['ids']));
|
||||
}
|
||||
if ($where['cate_id'] !== '') {
|
||||
$where['cate_id'] = explode(',', $where['cate_id']);
|
||||
foreach ($where['cate_id'] as $keys => &$items) {
|
||||
$where['cate_id'][$keys] = (int)$items;
|
||||
// 分类 / 品类券:统一整型化
|
||||
$where['cate_id'] = toIntArray($where['cate_id'] ?? '');
|
||||
$where['coupon_category_id'] = toIntArray($where['coupon_category_id'] ?? '');
|
||||
if (empty($where['cate_id'])) {
|
||||
unset($where['cate_id']);
|
||||
}
|
||||
if (empty($where['coupon_category_id'])) {
|
||||
unset($where['coupon_category_id']);
|
||||
}
|
||||
if (empty($where['sid'])) {
|
||||
unset($where['sid']);
|
||||
}
|
||||
if (empty($where['cid'])) {
|
||||
unset($where['cid']);
|
||||
}
|
||||
// 关键词截断,降低超长 LIKE 压力
|
||||
if (isset($where['store_name']) && is_string($where['store_name'])) {
|
||||
$where['store_name'] = mb_substr(trim($where['store_name']), 0, 50);
|
||||
if ($where['store_name'] === '') {
|
||||
unset($where['store_name']);
|
||||
}
|
||||
} else {
|
||||
$where['cate_id'] = [];
|
||||
}
|
||||
$list = $services->getUserList($where, $page, $limit, (int)$request->uid());
|
||||
|
||||
|
||||
@ -40,23 +40,11 @@ class CenterProductDao extends BaseDao implements ProductQueryInterface
|
||||
public function getCount(array $where)
|
||||
{
|
||||
return $this->search($where, false)->when(isset($where['sid']) && $where['sid'], function ($query) use ($where) {
|
||||
$query->whereIn('id', function ($query) use ($where) {
|
||||
$query->name('store_product_cate')->where('cate_id', is_array($where['sid']) ? 'in' : '=', $where['sid'])->field('product_id')->select();
|
||||
});
|
||||
$this->applyCategoryFilter($query, $where['sid'], false);
|
||||
})->when(isset($where['cid']) && $where['cid'], function ($query) use ($where) {
|
||||
$query->whereIn('id', function ($query) use ($where) {
|
||||
$query->name('store_product_cate')->whereIn('cate_id', function ($query) use ($where) {
|
||||
$query->name('store_category')->where('pid', is_array($where['cid']) ? 'in' : '=', $where['cid'])
|
||||
->whereOr('id', is_array($where['cid']) ? 'in' : '=', $where['cid'])->field('id')->select();
|
||||
})->field('product_id')->select();
|
||||
});
|
||||
$this->applyCategoryFilter($query, $where['cid'], true);
|
||||
})->when(!empty($where['coupon_category_id']), function ($query) use ($where) {
|
||||
$where['coupon_category_id'] = toIntArray($where['coupon_category_id']);
|
||||
$query->whereIn('id', function ($query) use ($where) {
|
||||
$query->name('store_product_cate')->whereIn('cate_id', function ($query) use ($where) {
|
||||
$query->name('store_category')->whereIn('pid', $where['coupon_category_id'])->field('id')->select();
|
||||
})->whereOr('cate_id', 'in', $where['coupon_category_id'])->field('product_id')->select();
|
||||
});
|
||||
$this->applyCategoryFilter($query, $where['coupon_category_id'], true);
|
||||
})->when(isset($where['ids']) && $where['ids'], function ($query) use ($where) {
|
||||
if ((isset($where['priceOrder']) && $where['priceOrder'] !== '') || (isset($where['salesOrder']) && $where['salesOrder'] !== '')) {
|
||||
$query->whereIn('id', $where['ids']);
|
||||
@ -231,23 +219,11 @@ class CenterProductDao extends BaseDao implements ProductQueryInterface
|
||||
return $this->search($where, false)->with($with)->when($page != 0 && $limit != 0, function ($query) use ($page, $limit) {
|
||||
$query->page($page, $limit);
|
||||
})->when(isset($where['sid']) && $where['sid'], function ($query) use ($where) {
|
||||
$query->whereIn('id', function ($query) use ($where) {
|
||||
$query->name('store_product_cate')->where('cate_id', is_array($where['sid']) ? 'in' : '=', $where['sid'])->field('product_id')->select();
|
||||
});
|
||||
$this->applyCategoryFilter($query, $where['sid'], false);
|
||||
})->when(isset($where['cid']) && $where['cid'], function ($query) use ($where) {
|
||||
$query->whereIn('id', function ($query) use ($where) {
|
||||
$query->name('store_product_cate')->whereIn('cate_id', function ($query) use ($where) {
|
||||
$query->name('store_category')->where('pid', is_array($where['cid']) ? 'in' : '=', $where['cid'])
|
||||
->whereOr('id', is_array($where['cid']) ? 'in' : '=', $where['cid'])->field('id')->select();
|
||||
})->field('product_id')->select();
|
||||
});
|
||||
$this->applyCategoryFilter($query, $where['cid'], true);
|
||||
})->when(!empty($where['coupon_category_id']), function ($query) use ($where) {
|
||||
$where['coupon_category_id'] = toIntArray($where['coupon_category_id']);
|
||||
$query->whereIn('id', function ($query) use ($where) {
|
||||
$query->name('store_product_cate')->whereIn('cate_id', function ($query) use ($where) {
|
||||
$query->name('store_category')->whereIn('pid', $where['coupon_category_id'])->field('id')->select();
|
||||
})->whereOr('cate_id', 'in', $where['coupon_category_id'])->field('product_id')->select();
|
||||
});
|
||||
$this->applyCategoryFilter($query, $where['coupon_category_id'], true);
|
||||
})->when(isset($where['ids']) && $where['ids'], function ($query) use ($where) {
|
||||
if ((isset($where['priceOrder']) && $where['priceOrder'] !== '') || (isset($where['salesOrder']) && $where['salesOrder'] !== '')) {
|
||||
$query->whereIn('id', $where['ids']);
|
||||
@ -258,22 +234,12 @@ class CenterProductDao extends BaseDao implements ProductQueryInterface
|
||||
$query->whereNotIn('id', function ($query) {
|
||||
$query->name('live_goods')->where('is_del', 0)->where('audit_status', '<>', 3)->field('product_id')->select();
|
||||
});
|
||||
})->when(isset($where['priceOrder']) && $where['priceOrder'] !== '', function ($query) use ($where) {
|
||||
if ($where['priceOrder'] === 'desc') {
|
||||
$query->order("price desc");
|
||||
} else {
|
||||
$query->order("price asc");
|
||||
}
|
||||
})->when(isset($where['newsOrder']) && $where['newsOrder'] !== '', function ($query) use ($where) {
|
||||
if ($where['newsOrder'] === 'news') {
|
||||
$query->order("id desc");
|
||||
}
|
||||
})->when(isset($where['salesOrder']) && $where['salesOrder'] !== '', function ($query) use ($where) {
|
||||
if ($where['salesOrder'] === 'desc') {
|
||||
$query->order("sales desc");
|
||||
} else {
|
||||
$query->order("sales asc");
|
||||
}
|
||||
})->when(isset($where['priceOrder']) && in_array($where['priceOrder'], ['asc', 'desc'], true), function ($query) use ($where) {
|
||||
$query->order('price ' . $where['priceOrder']);
|
||||
})->when(isset($where['newsOrder']) && $where['newsOrder'] === 'news', function ($query) {
|
||||
$query->order('id desc');
|
||||
})->when(isset($where['salesOrder']) && in_array($where['salesOrder'], ['asc', 'desc'], true), function ($query) use ($where) {
|
||||
$query->order('sales ' . $where['salesOrder']);
|
||||
})->when(!isset($where['ids']), function ($query) use ($where) {
|
||||
if (isset($where['timeOrder']) && $where['timeOrder'] == 1) {
|
||||
$query->order('id desc');
|
||||
@ -282,10 +248,15 @@ class CenterProductDao extends BaseDao implements ProductQueryInterface
|
||||
}
|
||||
})->when(!$page && $limit, function ($query) use ($limit) {
|
||||
$query->limit($limit);
|
||||
})->when(isset($where['store_label_id']), function ($query) use ($where) {
|
||||
$query->where(function ($query) use ($where) {
|
||||
foreach ($where['store_label_id'] as $value) {
|
||||
$query->whereOr('FIND_IN_SET(:value, label_list)', ['value' => $value]);
|
||||
})->when(!empty($where['store_label_id']), function ($query) use ($where) {
|
||||
$labelIds = toIntArray($where['store_label_id']);
|
||||
if (!$labelIds) {
|
||||
return;
|
||||
}
|
||||
$query->where(function ($query) use ($labelIds) {
|
||||
foreach ($labelIds as $index => $value) {
|
||||
// 避免循环复用同名绑定导致 PDO 只取最后一次
|
||||
$query->whereOr('FIND_IN_SET(' . (int)$value . ', label_list)');
|
||||
}
|
||||
});
|
||||
})->order('sort_order desc')->field($field)->select()->toArray();
|
||||
@ -489,4 +460,41 @@ class CenterProductDao extends BaseDao implements ProductQueryInterface
|
||||
}
|
||||
return $list;
|
||||
}
|
||||
|
||||
/**
|
||||
* 按分类筛选商品(与下单品类券校验一致:商品表 cate_id)
|
||||
* @param mixed $query
|
||||
* @param mixed $categoryId 分类 id 或逗号串/数组
|
||||
* @param bool $expandChildren true=展开子分类(一级/品类券);false=仅匹配自身(二级 sid)
|
||||
* @return void
|
||||
*/
|
||||
protected function applyCategoryFilter($query, $categoryId, bool $expandChildren = true): void
|
||||
{
|
||||
$cateIds = toIntArray($categoryId);
|
||||
if (!$cateIds) {
|
||||
$query->whereRaw('1 = 0');
|
||||
return;
|
||||
}
|
||||
if ($expandChildren) {
|
||||
/** @var \app\dao\product\product\StoreCategoryDao $categoryDao */
|
||||
$categoryDao = app()->make(\app\dao\product\product\StoreCategoryDao::class);
|
||||
$categoryRows = $categoryDao->getAllById($cateIds) ?: [];
|
||||
$cateIds = array_values(array_unique(array_map('intval', array_column($categoryRows, 'id'))));
|
||||
if (!$cateIds) {
|
||||
$query->whereRaw('1 = 0');
|
||||
return;
|
||||
}
|
||||
}
|
||||
$query->where(function ($q) use ($cateIds) {
|
||||
foreach ($cateIds as $index => $cid) {
|
||||
if ($index === 0) {
|
||||
$q->whereFindInSet('cate_id', $cid);
|
||||
} else {
|
||||
$q->whereOr(function ($sub) use ($cid) {
|
||||
$sub->whereFindInSet('cate_id', $cid);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -238,15 +238,34 @@ class CenterProductModel extends BaseModel
|
||||
*/
|
||||
public function searchCateIdAttr($query, $value)
|
||||
{
|
||||
if ($value) {
|
||||
if (is_array($value)) {
|
||||
$query->whereIn('id', function ($query) use ($value) {
|
||||
$query->name('store_product_cate')->where('cate_id', 'IN', $value)->whereOr('cate_pid', 'IN', $value)->field('product_id')->select();
|
||||
});
|
||||
} else {
|
||||
$query->whereFindInSet('cate_id', $value);
|
||||
}
|
||||
if (!$value) {
|
||||
return;
|
||||
}
|
||||
$cateIds = toIntArray($value);
|
||||
if (!$cateIds) {
|
||||
return;
|
||||
}
|
||||
// 展开传入分类及其子分类,再按商品 cate_id 匹配(与列表/用券逻辑一致)
|
||||
try {
|
||||
$categoryRows = app()->make(\app\dao\product\product\StoreCategoryDao::class)->getAllById($cateIds) ?: [];
|
||||
$expanded = array_values(array_unique(array_map('intval', array_column($categoryRows, 'id'))));
|
||||
if ($expanded) {
|
||||
$cateIds = $expanded;
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
// 分类服务不可用时回退为原始 id
|
||||
}
|
||||
$query->where(function ($q) use ($cateIds) {
|
||||
foreach ($cateIds as $index => $cid) {
|
||||
if ($index === 0) {
|
||||
$q->whereFindInSet('cate_id', $cid);
|
||||
} else {
|
||||
$q->whereOr(function ($sub) use ($cid) {
|
||||
$sub->whereFindInSet('cate_id', $cid);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user